Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 | 7 |
| 8 #include "SkMutex.h" | 8 #include "SkMutex.h" |
| 9 #include "SkOpCoincidence.h" | 9 #include "SkOpCoincidence.h" |
| 10 #include "SkOpContour.h" | 10 #include "SkOpContour.h" |
| 11 #include "SkPath.h" | 11 #include "SkPath.h" |
| 12 #include "SkPathOpsDebug.h" | 12 #include "SkPathOpsDebug.h" |
| 13 #include "SkString.h" | 13 #include "SkString.h" |
| 14 | 14 |
| 15 struct SkCoincidentSpans; | 15 class SkCoincidentSpans; |
| 16 | 16 |
| 17 #if DEBUG_VALIDATE | 17 #if DEBUG_VALIDATE |
| 18 extern bool FLAGS_runFail; | 18 extern bool FLAGS_runFail; |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 #if DEBUG_SORT | 21 #if DEBUG_SORT |
| 22 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; | 22 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; |
| 23 int SkPathOpsDebug::gSortCount; | 23 int SkPathOpsDebug::gSortCount; |
| 24 #endif | 24 #endif |
| 25 | 25 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 39 for (int index = 0; index < chaseArray.count(); ++index) { | 39 for (int index = 0; index < chaseArray.count(); ++index) { |
| 40 const SkOpSpanBase* entry = chaseArray[index]; | 40 const SkOpSpanBase* entry = chaseArray[index]; |
| 41 if (entry == span) { | 41 if (entry == span) { |
| 42 return true; | 42 return true; |
| 43 } | 43 } |
| 44 } | 44 } |
| 45 return false; | 45 return false; |
| 46 } | 46 } |
| 47 #endif | 47 #endif |
| 48 | 48 |
| 49 #if DEBUG_COINCIDENCE | 49 #if DEBUG_COINCIDENCE_VERBOSE |
| 50 enum GlitchType { | 50 enum GlitchType { |
| 51 kAddCorruptCoin_Glitch, | 51 kAddCorruptCoin_Glitch, |
| 52 kAddExpandedCoin_Glitch, | 52 kAddExpandedCoin_Glitch, |
| 53 kAddExpandedFail_Glitch, | |
| 54 kAddIfMissingCoin_Glitch, | |
| 53 kAddMissingCoin_Glitch, | 55 kAddMissingCoin_Glitch, |
| 56 kAddMissingExtend_Glitch, | |
| 57 kAddOrOverlap_Glitch, | |
| 54 kCollapsedCoin_Glitch, | 58 kCollapsedCoin_Glitch, |
| 55 kCollapsedDone_Glitch, | 59 kCollapsedDone_Glitch, |
| 56 kCollapsedOppValue_Glitch, | 60 kCollapsedOppValue_Glitch, |
| 57 kCollapsedSpan_Glitch, | 61 kCollapsedSpan_Glitch, |
| 58 kCollapsedWindValue_Glitch, | 62 kCollapsedWindValue_Glitch, |
| 59 kDeletedCoin_Glitch, | 63 kDeletedCoin_Glitch, |
| 60 kExpandCoin_Glitch, | 64 kExpandCoin_Glitch, |
| 61 kMarkCoinEnd_Glitch, | 65 kMarkCoinEnd_Glitch, |
| 62 kMarkCoinInsert_Glitch, | 66 kMarkCoinInsert_Glitch, |
| 67 kMarkCoinMissing_Glitch, | |
| 68 kMarkCoinStart_Glitch, | |
| 69 kMergeContained_Glitch, | |
| 63 kMissingCoin_Glitch, | 70 kMissingCoin_Glitch, |
| 64 kMissingDone_Glitch, | 71 kMissingDone_Glitch, |
| 65 kMissingIntersection_Glitch, | 72 kMissingIntersection_Glitch, |
| 66 kMoveMultiple_Glitch, | 73 kMoveMultiple_Glitch, |
| 74 kMoveNearbyClearAll_Glitch, | |
| 75 kMoveNearbyClearAll2_Glitch, | |
| 76 kMoveNearbyMerge_Glitch, | |
| 77 kMoveNearbyMergeFinal_Glitch, | |
| 78 kMoveNearbyRelease_Glitch, | |
| 79 kMoveNearbyReleaseFinal_Glitch, | |
| 80 kReleasedSpan_Glitch, | |
| 67 kUnaligned_Glitch, | 81 kUnaligned_Glitch, |
| 68 kUnalignedHead_Glitch, | 82 kUnalignedHead_Glitch, |
| 69 kUnalignedTail_Glitch, | 83 kUnalignedTail_Glitch, |
| 70 kUndetachedSpan_Glitch, | |
| 71 kUnmergedSpan_Glitch, | |
| 72 }; | 84 }; |
| 73 | 85 |
| 74 static const int kGlitchType_Count = kUnmergedSpan_Glitch + 1; | 86 static const int kGlitchType_Count = kUnalignedTail_Glitch + 1; |
| 75 | 87 |
| 76 struct SpanGlitch { | 88 struct SpanGlitch { |
| 77 const char* fStage; | 89 const char* fStage; |
| 78 const SkOpSpanBase* fBase; | 90 const SkOpSpanBase* fBase; |
| 79 const SkOpSpanBase* fSuspect; | 91 const SkOpSpanBase* fSuspect; |
| 80 const SkCoincidentSpans* fCoin; | |
| 81 const SkOpSegment* fSegment; | 92 const SkOpSegment* fSegment; |
| 93 const SkOpSegment* fOppSegment; | |
| 82 const SkOpPtT* fCoinSpan; | 94 const SkOpPtT* fCoinSpan; |
| 83 const SkOpPtT* fEndSpan; | 95 const SkOpPtT* fEndSpan; |
| 84 const SkOpPtT* fOppSpan; | 96 const SkOpPtT* fOppSpan; |
| 85 const SkOpPtT* fOppEndSpan; | 97 const SkOpPtT* fOppEndSpan; |
| 86 double fT; | 98 double fStartT; |
| 99 double fEndT; | |
| 100 double fOppStartT; | |
| 101 double fOppEndT; | |
| 87 SkPoint fPt; | 102 SkPoint fPt; |
| 88 GlitchType fType; | 103 GlitchType fType; |
| 89 }; | 104 }; |
| 90 | 105 |
| 91 struct SkPathOpsDebug::GlitchLog { | 106 struct SkPathOpsDebug::GlitchLog { |
| 92 SpanGlitch* recordCommon(GlitchType type, const char* stage) { | 107 SpanGlitch* recordCommon(GlitchType type, const char* stage) { |
| 93 SpanGlitch* glitch = fGlitches.push(); | 108 SpanGlitch* glitch = fGlitches.push(); |
| 94 glitch->fStage = stage; | 109 glitch->fStage = stage; |
| 95 glitch->fBase = nullptr; | 110 glitch->fBase = nullptr; |
| 96 glitch->fSuspect = nullptr; | 111 glitch->fSuspect = nullptr; |
| 97 glitch->fCoin = nullptr; | |
| 98 glitch->fSegment = nullptr; | 112 glitch->fSegment = nullptr; |
| 113 glitch->fOppSegment = nullptr; | |
| 99 glitch->fCoinSpan = nullptr; | 114 glitch->fCoinSpan = nullptr; |
| 100 glitch->fEndSpan = nullptr; | 115 glitch->fEndSpan = nullptr; |
| 101 glitch->fOppSpan = nullptr; | 116 glitch->fOppSpan = nullptr; |
| 102 glitch->fOppEndSpan = nullptr; | 117 glitch->fOppEndSpan = nullptr; |
| 103 glitch->fT = SK_ScalarNaN; | 118 glitch->fStartT = SK_ScalarNaN; |
| 119 glitch->fEndT = SK_ScalarNaN; | |
| 120 glitch->fOppStartT = SK_ScalarNaN; | |
| 121 glitch->fOppEndT = SK_ScalarNaN; | |
| 104 glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN }; | 122 glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN }; |
| 105 glitch->fType = type; | 123 glitch->fType = type; |
| 106 return glitch; | 124 return glitch; |
| 107 } | 125 } |
| 108 | 126 |
| 109 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, | 127 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, |
| 110 const SkOpSpanBase* suspect = NULL) { | 128 const SkOpSpanBase* suspect = NULL) { |
| 111 SpanGlitch* glitch = recordCommon(type, stage); | 129 SpanGlitch* glitch = recordCommon(type, stage); |
| 112 glitch->fBase = base; | 130 glitch->fBase = base; |
| 113 glitch->fSuspect = suspect; | 131 glitch->fSuspect = suspect; |
| 114 } | 132 } |
| 115 | 133 |
| 134 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, | |
| 135 const SkOpPtT* ptT) { | |
| 136 SpanGlitch* glitch = recordCommon(type, stage); | |
| 137 glitch->fBase = base; | |
| 138 glitch->fCoinSpan = ptT; | |
| 139 } | |
| 140 | |
| 116 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, | 141 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, |
| 117 const SkOpPtT* coinSpan) { | 142 const SkCoincidentSpans* opp = NULL) { |
| 118 SpanGlitch* glitch = recordCommon(type, stage); | 143 SpanGlitch* glitch = recordCommon(type, stage); |
| 119 glitch->fCoin = coin; | 144 glitch->fCoinSpan = coin->coinPtTStart(); |
| 120 glitch->fCoinSpan = coinSpan; | 145 glitch->fEndSpan = coin->coinPtTEnd(); |
| 146 if (opp) { | |
| 147 glitch->fOppSpan = opp->coinPtTStart(); | |
| 148 glitch->fOppEndSpan = opp->coinPtTEnd(); | |
| 149 } | |
| 121 } | 150 } |
| 122 | 151 |
| 123 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, | 152 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, |
| 124 const SkOpSegment* seg, double t, SkPoint pt) { | 153 const SkOpSegment* seg, double t, SkPoint pt) { |
| 125 SpanGlitch* glitch = recordCommon(type, stage); | 154 SpanGlitch* glitch = recordCommon(type, stage); |
| 126 glitch->fBase = base; | 155 glitch->fBase = base; |
| 127 glitch->fSegment = seg; | 156 glitch->fSegment = seg; |
| 128 glitch->fT = t; | 157 glitch->fStartT = t; |
| 129 glitch->fPt = pt; | 158 glitch->fPt = pt; |
| 130 } | 159 } |
| 131 | 160 |
| 132 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, do uble t, | 161 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, do uble t, |
| 133 SkPoint pt) { | 162 SkPoint pt) { |
| 134 SpanGlitch* glitch = recordCommon(type, stage); | 163 SpanGlitch* glitch = recordCommon(type, stage); |
| 135 glitch->fBase = base; | 164 glitch->fBase = base; |
| 136 glitch->fT = t; | 165 glitch->fStartT = t; |
| 137 glitch->fPt = pt; | 166 glitch->fPt = pt; |
| 138 } | 167 } |
| 139 | 168 |
| 140 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, | 169 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, |
| 141 const SkOpPtT* coinSpan, const SkOpPtT* endSpan) { | 170 const SkOpPtT* coinSpan, const SkOpPtT* endSpan) { |
| 142 SpanGlitch* glitch = recordCommon(type, stage); | 171 SpanGlitch* glitch = recordCommon(type, stage); |
| 143 glitch->fCoin = coin; | 172 glitch->fCoinSpan = coin->coinPtTStart(); |
| 144 glitch->fCoinSpan = coinSpan; | 173 glitch->fEndSpan = coin->coinPtTEnd(); |
| 145 glitch->fEndSpan = endSpan; | 174 glitch->fEndSpan = endSpan; |
| 175 glitch->fOppSpan = coinSpan; | |
| 176 glitch->fOppEndSpan = endSpan; | |
| 146 } | 177 } |
| 147 | 178 |
| 148 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, | 179 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, |
| 149 const SkOpSpanBase* suspect) { | 180 const SkOpSpanBase* base) { |
| 150 SpanGlitch* glitch = recordCommon(type, stage); | 181 SpanGlitch* glitch = recordCommon(type, stage); |
| 151 glitch->fSuspect = suspect; | 182 glitch->fBase = base; |
| 152 glitch->fCoin = coin; | 183 glitch->fCoinSpan = coin->coinPtTStart(); |
| 184 glitch->fEndSpan = coin->coinPtTEnd(); | |
| 153 } | 185 } |
| 154 | 186 |
| 155 void record(GlitchType type, const char* stage, const SkOpPtT* ptTS, const S kOpPtT* ptTE, | 187 void record(GlitchType type, const char* stage, const SkOpPtT* ptTS, const S kOpPtT* ptTE, |
| 156 const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) { | 188 const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) { |
| 157 SpanGlitch* glitch = recordCommon(type, stage); | 189 SpanGlitch* glitch = recordCommon(type, stage); |
| 158 glitch->fCoinSpan = ptTS; | 190 glitch->fCoinSpan = ptTS; |
| 159 glitch->fEndSpan = ptTE; | 191 glitch->fEndSpan = ptTE; |
| 160 glitch->fOppSpan = oPtTS; | 192 glitch->fOppSpan = oPtTS; |
| 161 glitch->fOppEndSpan = oPtTE; | 193 glitch->fOppEndSpan = oPtTE; |
| 162 } | 194 } |
| 163 | 195 |
| 196 void record(GlitchType type, const char* stage, const SkOpSegment* seg, doub le startT, | |
| 197 double endT, const SkOpSegment* oppSeg, double oppStartT, double opp EndT) { | |
| 198 SpanGlitch* glitch = recordCommon(type, stage); | |
| 199 glitch->fSegment = seg; | |
| 200 glitch->fStartT = startT; | |
| 201 glitch->fEndT = endT; | |
| 202 glitch->fOppSegment = oppSeg; | |
| 203 glitch->fOppStartT = oppStartT; | |
| 204 glitch->fOppEndT = oppEndT; | |
| 205 } | |
| 206 | |
| 207 void record(GlitchType type, const char* stage, const SkOpSegment* seg, | |
| 208 const SkOpSpan* span) { | |
| 209 SpanGlitch* glitch = recordCommon(type, stage); | |
| 210 glitch->fSegment = seg; | |
| 211 glitch->fBase = span; | |
| 212 } | |
| 213 | |
| 214 void record(GlitchType type, const char* stage, double t, const SkOpSpanBase * span) { | |
| 215 SpanGlitch* glitch = recordCommon(type, stage); | |
| 216 glitch->fStartT = t; | |
| 217 glitch->fBase = span; | |
| 218 } | |
| 219 | |
| 220 void record(GlitchType type, const char* stage, const SkOpSegment* seg) { | |
| 221 SpanGlitch* glitch = recordCommon(type, stage); | |
| 222 glitch->fSegment = seg; | |
| 223 } | |
| 224 | |
| 225 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, | |
| 226 const SkOpPtT* ptT) { | |
| 227 SpanGlitch* glitch = recordCommon(type, stage); | |
| 228 glitch->fCoinSpan = coin->coinPtTStart(); | |
| 229 glitch->fEndSpan = ptT; | |
| 230 } | |
| 231 | |
| 164 SkTDArray<SpanGlitch> fGlitches; | 232 SkTDArray<SpanGlitch> fGlitches; |
| 165 }; | 233 }; |
| 234 #endif | |
| 166 | 235 |
| 236 void SkPathOpsDebug::ShowActiveSpans(SkOpContourHead* contourList) { | |
| 237 #if DEBUG_ACTIVE_SPANS | |
| 238 SkOpContour* contour = contourList; | |
| 239 do { | |
| 240 contour->debugShowActiveSpans(); | |
| 241 } while ((contour = contour->next())); | |
| 242 #endif | |
| 243 } | |
| 244 | |
| 245 #if DEBUG_COINCIDENCE | |
| 167 void SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList, const char* id) { | 246 void SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList, const char* id) { |
| 247 contourList->globalState()->debugSetCheckHealth(true); | |
| 248 #if DEBUG_COINCIDENCE_VERBOSE | |
| 168 GlitchLog glitches; | 249 GlitchLog glitches; |
| 169 const SkOpContour* contour = contourList; | 250 const SkOpContour* contour = contourList; |
| 170 const SkOpCoincidence* coincidence = contour->globalState()->coincidence(); | 251 const SkOpCoincidence* coincidence = contour->globalState()->coincidence(); |
| 252 coincidence->debugCheckValid(id, &glitches); // don't call validate; spans m ay be inconsistent | |
| 171 do { | 253 do { |
| 172 contour->debugCheckHealth(id, &glitches); | 254 contour->debugCheckHealth(id, &glitches); |
| 173 contour->debugMissingCoincidence(id, &glitches, coincidence); | 255 contour->debugMissingCoincidence(id, &glitches); |
| 174 } while ((contour = contour->next())); | 256 } while ((contour = contour->next())); |
| 175 coincidence->debugFixAligned(id, &glitches); | 257 coincidence->debugRemoveCollapsed(id, &glitches); |
| 176 coincidence->debugAddMissing(id, &glitches); | 258 coincidence->debugAddMissing(id, &glitches); |
| 177 coincidence->debugExpand(id, &glitches); | 259 coincidence->debugExpand(id, &glitches); |
| 178 coincidence->debugAddExpanded(id, &glitches); | 260 coincidence->debugAddExpanded(id, &glitches); |
| 179 coincidence->debugMark(id, &glitches); | 261 coincidence->debugMark(id, &glitches); |
| 262 coincidence->debugReorder(id, &glitches); | |
| 180 unsigned mask = 0; | 263 unsigned mask = 0; |
| 181 for (int index = 0; index < glitches.fGlitches.count(); ++index) { | 264 for (int index = 0; index < glitches.fGlitches.count(); ++index) { |
| 182 const SpanGlitch& glitch = glitches.fGlitches[index]; | 265 const SpanGlitch& glitch = glitches.fGlitches[index]; |
| 183 mask |= 1 << glitch.fType; | 266 mask |= 1 << glitch.fType; |
| 184 } | 267 } |
| 185 for (int index = 0; index < kGlitchType_Count; ++index) { | 268 for (int index = 0; index < kGlitchType_Count; ++index) { |
| 186 SkDebugf(mask & (1 << index) ? "x" : "-"); | 269 SkDebugf(mask & (1 << index) ? "x" : "-"); |
| 187 } | 270 } |
| 188 SkDebugf(" %s\n", id); | 271 SkDebugf(" %s\n", id); |
| 272 for (int index = 0; index < glitches.fGlitches.count(); ++index) { | |
| 273 const SpanGlitch& glitch = glitches.fGlitches[index]; | |
| 274 SkDebugf("%02d: ", index); | |
| 275 if (glitch.fBase) { | |
| 276 SkDebugf(" base=%d", glitch.fBase->debugID()); | |
| 277 } | |
| 278 if (glitch.fSuspect) { | |
| 279 SkDebugf(" base=%d", glitch.fSuspect->debugID()); | |
| 280 } | |
| 281 if (glitch.fSegment) { | |
| 282 SkDebugf(" segment=%d", glitch.fSegment->debugID()); | |
| 283 } | |
| 284 if (glitch.fCoinSpan) { | |
| 285 SkDebugf(" coinSpan=%d", glitch.fCoinSpan->debugID()); | |
| 286 } | |
| 287 if (glitch.fEndSpan) { | |
| 288 SkDebugf(" endSpan=%d", glitch.fEndSpan->debugID()); | |
| 289 } | |
| 290 if (glitch.fOppSpan) { | |
| 291 SkDebugf(" oppSpan=%d", glitch.fOppSpan->debugID()); | |
| 292 } | |
| 293 if (glitch.fOppEndSpan) { | |
| 294 SkDebugf(" oppEndSpan=%d", glitch.fOppEndSpan->debugID()); | |
| 295 } | |
| 296 if (!SkScalarIsNaN(glitch.fStartT)) { | |
| 297 SkDebugf(" startT=%g", glitch.fStartT); | |
| 298 } | |
| 299 if (!SkScalarIsNaN(glitch.fEndT)) { | |
| 300 SkDebugf(" endT=%g", glitch.fEndT); | |
| 301 } | |
| 302 if (glitch.fOppSegment) { | |
| 303 SkDebugf(" segment=%d", glitch.fOppSegment->debugID()); | |
| 304 } | |
| 305 if (!SkScalarIsNaN(glitch.fOppStartT)) { | |
| 306 SkDebugf(" oppStartT=%g", glitch.fOppStartT); | |
| 307 } | |
| 308 if (!SkScalarIsNaN(glitch.fOppEndT)) { | |
| 309 SkDebugf(" oppEndT=%g", glitch.fOppEndT); | |
| 310 } | |
| 311 if (!SkScalarIsNaN(glitch.fPt.fX) || !SkScalarIsNaN(glitch.fPt.fY)) { | |
| 312 SkDebugf(" pt=%g,%g", glitch.fPt.fX, glitch.fPt.fY); | |
| 313 } | |
| 314 switch (glitch.fType) { | |
| 315 case kAddCorruptCoin_Glitch: SkDebugf(" AddCorruptCoin"); break; | |
| 316 case kAddExpandedCoin_Glitch: SkDebugf(" AddExpandedCoin"); break; | |
| 317 case kAddExpandedFail_Glitch: SkDebugf(" AddExpandedFail"); break; | |
| 318 case kAddIfMissingCoin_Glitch: SkDebugf(" AddIfMissingCoin"); break; | |
| 319 case kAddMissingCoin_Glitch: SkDebugf(" AddMissingCoin"); break; | |
| 320 case kAddMissingExtend_Glitch: SkDebugf(" AddMissingExtend"); break; | |
| 321 case kAddOrOverlap_Glitch: SkDebugf(" AAddOrOverlap"); break; | |
| 322 case kCollapsedCoin_Glitch: SkDebugf(" CollapsedCoin"); break; | |
| 323 case kCollapsedDone_Glitch: SkDebugf(" CollapsedDone"); break; | |
| 324 case kCollapsedOppValue_Glitch: SkDebugf(" CollapsedOppValue"); brea k; | |
| 325 case kCollapsedSpan_Glitch: SkDebugf(" CollapsedSpan"); break; | |
| 326 case kCollapsedWindValue_Glitch: SkDebugf(" CollapsedWindValue"); br eak; | |
| 327 case kDeletedCoin_Glitch: SkDebugf(" DeletedCoin"); break; | |
| 328 case kExpandCoin_Glitch: SkDebugf(" ExpandCoin"); break; | |
| 329 case kMarkCoinEnd_Glitch: SkDebugf(" MarkCoinEnd"); break; | |
| 330 case kMarkCoinInsert_Glitch: SkDebugf(" MarkCoinInsert"); break; | |
| 331 case kMarkCoinMissing_Glitch: SkDebugf(" MarkCoinMissing"); break; | |
| 332 case kMarkCoinStart_Glitch: SkDebugf(" MarkCoinStart"); break; | |
| 333 case kMergeContained_Glitch: SkDebugf(" MergeContained"); break; | |
| 334 case kMissingCoin_Glitch: SkDebugf(" MissingCoin"); break; | |
| 335 case kMissingDone_Glitch: SkDebugf(" MissingDone"); break; | |
| 336 case kMissingIntersection_Glitch: SkDebugf(" MissingIntersection"); break; | |
| 337 case kMoveMultiple_Glitch: SkDebugf(" MoveMultiple"); break; | |
| 338 case kMoveNearbyClearAll_Glitch: SkDebugf(" MoveNearbyClearAll"); br eak; | |
| 339 case kMoveNearbyClearAll2_Glitch: SkDebugf(" MoveNearbyClearAll2"); break; | |
| 340 case kMoveNearbyMerge_Glitch: SkDebugf(" MoveNearbyMerge"); break; | |
| 341 case kMoveNearbyMergeFinal_Glitch: SkDebugf(" MoveNearbyMergeFinal") ; break; | |
| 342 case kMoveNearbyRelease_Glitch: SkDebugf(" MoveNearbyRelease"); brea k; | |
| 343 case kMoveNearbyReleaseFinal_Glitch: SkDebugf(" MoveNearbyReleaseFin al"); break; | |
| 344 case kReleasedSpan_Glitch: SkDebugf(" ReleasedSpan"); break; | |
| 345 case kUnaligned_Glitch: SkDebugf(" Unaligned"); break; | |
| 346 case kUnalignedHead_Glitch: SkDebugf(" UnalignedHead"); break; | |
| 347 case kUnalignedTail_Glitch: SkDebugf(" UnalignedTail"); break; | |
| 348 default: SkASSERT(0); | |
| 349 } | |
| 350 SkDebugf("\n"); | |
| 351 } | |
| 352 contourList->globalState()->debugSetCheckHealth(false); | |
| 353 #if DEBUG_ACTIVE_SPANS | |
| 354 SkDebugf("active after %s:\n", id); | |
| 355 ShowActiveSpans(contourList); | |
| 356 #endif | |
| 357 #endif | |
| 189 } | 358 } |
| 190 #endif | 359 #endif |
| 191 | 360 |
| 192 #if defined SK_DEBUG || !FORCE_RELEASE | 361 #if defined SK_DEBUG || !FORCE_RELEASE |
| 193 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { | 362 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { |
| 194 size_t len = strlen(str); | 363 size_t len = strlen(str); |
| 195 bool num = false; | 364 bool num = false; |
| 196 for (size_t idx = 0; idx < len; ++idx) { | 365 for (size_t idx = 0; idx < len; ++idx) { |
| 197 if (num && str[idx] == 'e') { | 366 if (num && str[idx] == 'e') { |
| 198 if (len + 2 >= bufferLen) { | 367 if (len + 2 >= bufferLen) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 247 SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filenam e) {\n", functionName); | 416 SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filenam e) {\n", functionName); |
| 248 if (strcmp("skphealth_com76", functionName) == 0) { | 417 if (strcmp("skphealth_com76", functionName) == 0) { |
| 249 SkDebugf("found it\n"); | 418 SkDebugf("found it\n"); |
| 250 } | 419 } |
| 251 } | 420 } |
| 252 | 421 |
| 253 static const char* gOpStrs[] = { | 422 static const char* gOpStrs[] = { |
| 254 "kDifference_SkPathOp", | 423 "kDifference_SkPathOp", |
| 255 "kIntersect_SkPathOp", | 424 "kIntersect_SkPathOp", |
| 256 "kUnion_SkPathOp", | 425 "kUnion_SkPathOp", |
| 257 "kXor_PathOp", | 426 "kXOR_PathOp", |
| 258 "kReverseDifference_SkPathOp", | 427 "kReverseDifference_SkPathOp", |
| 259 }; | 428 }; |
| 260 | 429 |
| 261 const char* SkPathOpsDebug::OpStr(SkPathOp op) { | 430 const char* SkPathOpsDebug::OpStr(SkPathOp op) { |
| 262 return gOpStrs[op]; | 431 return gOpStrs[op]; |
| 263 } | 432 } |
| 264 | 433 |
| 265 static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) { | 434 static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) { |
| 266 SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathT wo, gOpStrs[op]); | 435 SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathT wo, gOpStrs[op]); |
| 267 SkDebugf("}\n"); | 436 SkDebugf("}\n"); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 405 } | 574 } |
| 406 | 575 |
| 407 void SkDRect::debugInit() { | 576 void SkDRect::debugInit() { |
| 408 fLeft = fTop = fRight = fBottom = SK_ScalarNaN; | 577 fLeft = fTop = fRight = fBottom = SK_ScalarNaN; |
| 409 } | 578 } |
| 410 | 579 |
| 411 #include "SkOpAngle.h" | 580 #include "SkOpAngle.h" |
| 412 #include "SkOpSegment.h" | 581 #include "SkOpSegment.h" |
| 413 | 582 |
| 414 #if DEBUG_COINCIDENCE | 583 #if DEBUG_COINCIDENCE |
| 415 void SkOpSegment::debugAddAlignIntersection(const char* id, SkPathOpsDebug::Glit chLog* log, | 584 // commented-out lines keep this in sync with addT() |
| 416 const SkOpPtT& endPtT, const SkPoint& oldPt, const SkOpContourHead* con tourList) const { | 585 const SkOpPtT* SkOpSegment::debugAddT(double t, AliasMatch allowAlias, bool* al located) const { |
| 417 const SkPoint& newPt = endPtT.fPt; | 586 debugValidate(); |
| 418 if (newPt == oldPt) { | 587 SkPoint pt = this->ptAtT(t); |
| 419 return; | 588 const SkOpSpanBase* span = &fHead; |
| 420 } | |
| 421 SkPoint line[2] = { newPt, oldPt }; | |
| 422 SkPathOpsBounds lineBounds; | |
| 423 lineBounds.setBounds(line, 2); | |
| 424 SkDLine aLine; | |
| 425 aLine.set(line); | |
| 426 const SkOpContour* current = contourList; | |
| 427 do { | 589 do { |
| 428 if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) { | 590 const SkOpPtT* result = span->ptT(); |
| 429 continue; | 591 const SkOpPtT* loop; |
| 592 bool duplicatePt; | |
| 593 if (t == result->fT) { | |
| 594 goto bumpSpan; | |
| 430 } | 595 } |
| 431 const SkOpSegment* segment = current->first(); | 596 if (this->match(result, this, t, pt, allowAlias)) { |
| 432 do { | 597 // see if any existing alias matches segment, pt, and t |
| 433 if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) { | 598 loop = result->next(); |
| 434 continue; | 599 duplicatePt = false; |
| 600 while (loop != result) { | |
| 601 bool ptMatch = loop->fPt == pt; | |
| 602 if (loop->segment() == this && loop->fT == t && ptMatch) { | |
| 603 goto bumpSpan; | |
| 604 } | |
| 605 duplicatePt |= ptMatch; | |
| 606 loop = loop->next(); | |
| 435 } | 607 } |
| 436 if (newPt == segment->fPts[0]) { | 608 if (kNoAliasMatch == allowAlias) { |
| 437 continue; | 609 bumpSpan: |
| 610 // span->bumpSpanAdds(); | |
| 611 return result; | |
| 438 } | 612 } |
| 439 if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { | 613 // SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator); |
| 440 continue; | 614 // alias->init(result->span(), t, pt, duplicatePt); |
| 615 // result->insert(alias); | |
| 616 // result->span()->unaligned(); | |
| 617 this->debugValidate(); | |
| 618 // #if DEBUG_ADD_T | |
| 619 // SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, | |
| 620 // alias->segment()->debugID(), alias->span()->debugID()); | |
| 621 // #endif | |
| 622 // span->bumpSpanAdds(); | |
| 623 if (allocated) { | |
| 624 *allocated = true; | |
| 441 } | 625 } |
| 442 if (oldPt == segment->fPts[0]) { | 626 return nullptr; |
| 443 continue; | 627 } |
| 628 if (t < result->fT) { | |
| 629 const SkOpSpan* prev = result->span()->prev(); | |
| 630 if (!prev) { | |
| 631 return nullptr; // FIXME: this is a fail case; nullptr return e lsewhere means result was allocated in non-const version | |
| 444 } | 632 } |
| 445 if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { | 633 // SkOpSpan* span = insert(prev, allocator); |
| 446 continue; | 634 // span->init(this, prev, t, pt); |
| 635 this->debugValidate(); | |
| 636 // #if DEBUG_ADD_T | |
| 637 // SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, | |
| 638 // span->segment()->debugID(), span->debugID()); | |
| 639 // #endif | |
| 640 // span->bumpSpanAdds(); | |
| 641 if (allocated) { | |
| 642 *allocated = true; | |
| 447 } | 643 } |
| 448 if (endPtT.debugContains(segment)) { | 644 return nullptr; |
| 449 continue; | |
| 450 } | |
| 451 SkIntersections i; | |
| 452 switch (segment->fVerb) { | |
| 453 case SkPath::kLine_Verb: { | |
| 454 SkDLine bLine; | |
| 455 bLine.set(segment->fPts); | |
| 456 i.intersect(bLine, aLine); | |
| 457 } break; | |
| 458 case SkPath::kQuad_Verb: { | |
| 459 SkDQuad bQuad; | |
| 460 bQuad.set(segment->fPts); | |
| 461 i.intersect(bQuad, aLine); | |
| 462 } break; | |
| 463 case SkPath::kConic_Verb: { | |
| 464 SkDConic bConic; | |
| 465 bConic.set(segment->fPts, segment->fWeight); | |
| 466 i.intersect(bConic, aLine); | |
| 467 } break; | |
| 468 case SkPath::kCubic_Verb: { | |
| 469 SkDCubic bCubic; | |
| 470 bCubic.set(segment->fPts); | |
| 471 i.intersect(bCubic, aLine); | |
| 472 } break; | |
| 473 default: | |
| 474 SkASSERT(0); | |
| 475 } | |
| 476 if (i.used()) { | |
| 477 SkASSERT(i.used() == 1); | |
| 478 SkASSERT(!zero_or_one(i[0][0])); | |
| 479 SkOpSpanBase* checkSpan = fHead.next(); | |
| 480 while (!checkSpan->final()) { | |
| 481 if (checkSpan->contains(segment)) { | |
| 482 goto nextSegment; | |
| 483 } | |
| 484 checkSpan = checkSpan->upCast()->next(); | |
| 485 } | |
| 486 log->record(kMissingIntersection_Glitch, id, checkSpan, segment, i[0][0], newPt); | |
| 487 } | |
| 488 nextSegment: | |
| 489 ; | |
| 490 } while ((segment = segment->next())); | |
| 491 } while ((current = current->next())); | |
| 492 } | |
| 493 | |
| 494 bool SkOpSegment::debugAddMissing(double t, const SkOpSegment* opp) const { | |
| 495 const SkOpSpanBase* existing = nullptr; | |
| 496 const SkOpSpanBase* test = &fHead; | |
| 497 double testT; | |
| 498 do { | |
| 499 if ((testT = test->ptT()->fT) >= t) { | |
| 500 if (testT == t) { | |
| 501 existing = test; | |
| 502 } | |
| 503 break; | |
| 504 } | 645 } |
| 505 } while ((test = test->upCast()->next())); | 646 SkASSERT(span != &fTail); |
| 506 return !existing || !existing->debugContains(opp); | 647 } while ((span = span->upCast()->next())); |
| 507 } | 648 SkASSERT(0); |
| 508 | 649 return nullptr; |
| 509 void SkOpSegment::debugAlign(const char* id, SkPathOpsDebug::GlitchLog* glitches ) const { | |
| 510 const SkOpSpanBase* span = &fHead; | |
| 511 if (!span->aligned()) { | |
| 512 if (!span->debugAlignedEnd(0, fPts[0])) { | |
| 513 glitches->record(kUnalignedHead_Glitch, id, span); | |
| 514 } | |
| 515 } | |
| 516 while ((span = span->upCast()->next())) { | |
| 517 if (span == &fTail) { | |
| 518 break; | |
| 519 } | |
| 520 if (!span->aligned()) { | |
| 521 glitches->record(kUnaligned_Glitch, id, span); | |
| 522 } | |
| 523 } | |
| 524 if (!span->aligned()) { | |
| 525 span->debugAlignedEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); | |
| 526 } | |
| 527 if (this->collapsed()) { | |
| 528 const SkOpSpan* span = &fHead; | |
| 529 do { | |
| 530 if (span->windValue()) { | |
| 531 glitches->record(kCollapsedWindValue_Glitch, id, span); | |
| 532 } | |
| 533 if (span->oppValue()) { | |
| 534 glitches->record(kCollapsedOppValue_Glitch, id, span); | |
| 535 } | |
| 536 if (!span->done()) { | |
| 537 glitches->record(kCollapsedDone_Glitch, id, span); | |
| 538 } | |
| 539 } while ((span = span->next()->upCastable())); | |
| 540 } | |
| 541 } | 650 } |
| 542 #endif | 651 #endif |
| 543 | 652 |
| 544 #if DEBUG_ANGLE | 653 #if DEBUG_ANGLE |
| 545 void SkOpSegment::debugCheckAngleCoin() const { | 654 void SkOpSegment::debugCheckAngleCoin() const { |
| 546 const SkOpSpanBase* base = &fHead; | 655 const SkOpSpanBase* base = &fHead; |
| 547 const SkOpSpan* span; | 656 const SkOpSpan* span; |
| 548 do { | 657 do { |
| 549 const SkOpAngle* angle = base->fromAngle(); | 658 const SkOpAngle* angle = base->fromAngle(); |
| 550 if (angle && angle->fCheckCoincidence) { | 659 if (angle && angle->debugCheckCoincidence()) { |
| 551 angle->debugCheckNearCoincidence(); | 660 angle->debugCheckNearCoincidence(); |
| 552 } | 661 } |
| 553 if (base->final()) { | 662 if (base->final()) { |
| 554 break; | 663 break; |
| 555 } | 664 } |
| 556 span = base->upCast(); | 665 span = base->upCast(); |
| 557 angle = span->toAngle(); | 666 angle = span->toAngle(); |
| 558 if (angle && angle->fCheckCoincidence) { | 667 if (angle && angle->debugCheckCoincidence()) { |
| 559 angle->debugCheckNearCoincidence(); | 668 angle->debugCheckNearCoincidence(); |
| 560 } | 669 } |
| 561 } while ((base = span->next())); | 670 } while ((base = span->next())); |
| 562 } | 671 } |
| 563 #endif | 672 #endif |
| 564 | 673 |
| 565 #if DEBUG_COINCIDENCE | 674 #if DEBUG_COINCIDENCE_VERBOSE |
| 566 // this mimics the order of the checks in handle coincidence | 675 // this mimics the order of the checks in handle coincidence |
| 567 void SkOpSegment::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* gl itches) const { | 676 void SkOpSegment::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* gl itches) const { |
| 568 debugMoveMultiples(id, glitches); | 677 debugMoveMultiples(id, glitches); |
| 569 debugFindCollapsed(id, glitches); | |
| 570 debugMoveNearby(id, glitches); | 678 debugMoveNearby(id, glitches); |
| 571 debugAlign(id, glitches); | 679 debugMissingCoincidence(id, glitches); |
| 572 debugAddAlignIntersections(id, glitches, this->globalState()->contourHead()) ; | |
| 573 | |
| 574 } | 680 } |
| 575 | 681 |
| 576 void SkOpSegment::debugFindCollapsed(const char* id, SkPathOpsDebug::GlitchLog* glitches) const { | 682 // commented-out lines keep this in sync with clearAll() |
| 577 if (fHead.contains(&fTail)) { | 683 void SkOpSegment::debugClearAll(const char* id, SkPathOpsDebug::GlitchLog* glitc hes) const { |
| 578 const SkOpSpan* span = this->head(); | 684 const SkOpSpan* span = &fHead; |
| 579 bool missingDone = false; | 685 do { |
| 580 do { | 686 this->debugClearOne(span, id, glitches); |
| 581 missingDone |= !span->done(); | 687 } while ((span = span->next()->upCastable())); |
| 582 } while ((span = span->next()->upCastable())); | 688 this->globalState()->coincidence()->debugRelease(id, glitches, this); |
| 583 if (missingDone) { | 689 } |
| 584 glitches->record(kMissingDone_Glitch, id, &fHead); | 690 |
| 585 } | 691 // commented-out lines keep this in sync with clearOne() |
| 586 if (!fHead.debugAlignedEnd(0, fHead.pt())) { | 692 void SkOpSegment::debugClearOne(const SkOpSpan* span, const char* id, SkPathOpsD ebug::GlitchLog* glitches) const { |
| 587 glitches->record(kUnalignedHead_Glitch, id, &fHead); | 693 if (span->windValue()) glitches->record(kCollapsedWindValue_Glitch, id, span ); |
| 588 } | 694 if (span->oppValue()) glitches->record(kCollapsedOppValue_Glitch, id, span); |
| 589 if (!fTail.aligned()) { | 695 if (!span->done()) glitches->record(kCollapsedDone_Glitch, id, span); |
| 590 glitches->record(kUnalignedTail_Glitch, id, &fTail); | |
| 591 } | |
| 592 } | |
| 593 } | 696 } |
| 594 #endif | 697 #endif |
| 595 | 698 |
| 596 SkOpAngle* SkOpSegment::debugLastAngle() { | 699 SkOpAngle* SkOpSegment::debugLastAngle() { |
| 597 SkOpAngle* result = nullptr; | 700 SkOpAngle* result = nullptr; |
| 598 SkOpSpan* span = this->head(); | 701 SkOpSpan* span = this->head(); |
| 599 do { | 702 do { |
| 600 if (span->toAngle()) { | 703 if (span->toAngle()) { |
| 601 SkASSERT(!result); | 704 SkASSERT(!result); |
| 602 result = span->toAngle(); | 705 result = span->toAngle(); |
| 603 } | 706 } |
| 604 } while ((span = span->next()->upCastable())); | 707 } while ((span = span->next()->upCastable())); |
| 605 SkASSERT(result); | 708 SkASSERT(result); |
| 606 return result; | 709 return result; |
| 607 } | 710 } |
| 608 | 711 |
| 609 #if DEBUG_COINCIDENCE | 712 #if DEBUG_COINCIDENCE |
| 610 void SkOpSegment::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log, | 713 // commented-out lines keep this in sync with ClearVisited |
| 611 const SkOpCoincidence* coincidences) const { | 714 void SkOpSegment::DebugClearVisited(const SkOpSpanBase* span) { |
| 612 if (this->verb() != SkPath::kLine_Verb) { | 715 // reset visited flag back to false |
| 613 return; | 716 do { |
| 614 } | 717 const SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; |
| 718 while ((ptT = ptT->next()) != stopPtT) { | |
| 719 const SkOpSegment* opp = ptT->segment(); | |
| 720 opp->resetDebugVisited(); | |
| 721 } | |
| 722 } while (!span->final() && (span = span->upCast()->next())); | |
| 723 } | |
| 724 #endif | |
| 725 | |
| 726 #if DEBUG_COINCIDENCE_VERBOSE | |
| 727 // commented-out lines keep this in sync with missingCoincidence() | |
| 728 // look for pairs of undetected coincident curves | |
| 729 // assumes that segments going in have visited flag clear | |
| 730 // Even though pairs of curves correct detect coincident runs, a run may be miss ed | |
| 731 // if the coincidence is a product of multiple intersections. For instance, give n | |
| 732 // curves A, B, and C: | |
| 733 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near | |
| 734 // the end of C that the intersection is replaced with the end of C. | |
| 735 // Even though A-B correctly do not detect an intersection at point 2, | |
| 736 // the resulting run from point 1 to point 2 is coincident on A and B. | |
| 737 void SkOpSegment::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log) const { | |
| 615 if (this->done()) { | 738 if (this->done()) { |
| 616 return; | 739 return; |
| 617 } | 740 } |
| 618 const SkOpSpan* prior = nullptr; | 741 const SkOpSpan* prior = nullptr; |
| 619 const SkOpSpanBase* spanBase = &fHead; | 742 const SkOpSpanBase* spanBase = &fHead; |
| 743 // bool result = false; | |
| 620 do { | 744 do { |
| 621 const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; | 745 const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; |
| 622 SkASSERT(ptT->span() == spanBase); | 746 SkASSERT(ptT->span() == spanBase); |
| 623 while ((ptT = ptT->next()) != spanStopPtT) { | 747 while ((ptT = ptT->next()) != spanStopPtT) { |
| 624 if (ptT->deleted()) { | 748 if (ptT->deleted()) { |
| 625 continue; | 749 continue; |
| 626 } | 750 } |
| 627 SkOpSegment* opp = ptT->span()->segment(); | 751 const SkOpSegment* opp = ptT->span()->segment(); |
| 628 // if (opp->verb() == SkPath::kLine_Verb) { | |
| 629 // continue; | |
| 630 // } | |
| 631 if (opp->done()) { | 752 if (opp->done()) { |
| 632 continue; | 753 continue; |
| 633 } | 754 } |
| 634 // when opp is encounted the 1st time, continue; on 2nd encounter, l ook for coincidence | 755 // when opp is encounted the 1st time, continue; on 2nd encounter, l ook for coincidence |
| 635 if (!opp->visited()) { | 756 if (!opp->debugVisited()) { |
| 636 continue; | 757 continue; |
| 637 } | 758 } |
| 638 if (spanBase == &fHead) { | 759 if (spanBase == &fHead) { |
| 639 continue; | 760 continue; |
| 640 } | 761 } |
| 762 if (ptT->segment() == this) { | |
| 763 continue; | |
| 764 } | |
| 641 const SkOpSpan* span = spanBase->upCastable(); | 765 const SkOpSpan* span = spanBase->upCastable(); |
| 642 // FIXME?: this assumes that if the opposite segment is coincident t hen no more | 766 // FIXME?: this assumes that if the opposite segment is coincident t hen no more |
| 643 // coincidence needs to be detected. This may not be true. | 767 // coincidence needs to be detected. This may not be true. |
| 644 if (span && span->segment() != opp && span->containsCoincidence(opp) ) { | 768 if (span && span->segment() != opp && span->containsCoincidence(opp) ) { // debug has additional condition since it may be called before inner dupli cate points have been deleted |
|
herb_g
2016/07/18 15:13:39
Comments on next line?
caryclark
2016/07/18 15:55:49
The crazy formatting here is so that SkOpSegment::
| |
| 645 continue; | 769 continue; |
| 646 } | 770 } |
| 647 if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) { | 771 if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) { // debug has additional condition since it may be called before inner duplicate points have been deleted |
| 648 continue; | 772 continue; |
| 649 } | 773 } |
| 650 const SkOpPtT* priorPtT = nullptr, * priorStopPtT; | 774 const SkOpPtT* priorPtT = nullptr, * priorStopPtT; |
| 651 // find prior span containing opp segment | 775 // find prior span containing opp segment |
| 652 const SkOpSegment* priorOpp = nullptr; | 776 const SkOpSegment* priorOpp = nullptr; |
| 653 const SkOpSpan* priorTest = spanBase->prev(); | 777 const SkOpSpan* priorTest = spanBase->prev(); |
| 654 while (!priorOpp && priorTest) { | 778 while (!priorOpp && priorTest) { |
| 655 priorStopPtT = priorPtT = priorTest->ptT(); | 779 priorStopPtT = priorPtT = priorTest->ptT(); |
| 656 while ((priorPtT = priorPtT->next()) != priorStopPtT) { | 780 while ((priorPtT = priorPtT->next()) != priorStopPtT) { |
| 657 if (priorPtT->deleted()) { | 781 if (priorPtT->deleted()) { |
| 658 continue; | 782 continue; |
| 659 } | 783 } |
| 660 SkOpSegment* segment = priorPtT->span()->segment(); | 784 SkOpSegment* segment = priorPtT->span()->segment(); |
| 661 if (segment == opp) { | 785 if (segment == opp) { |
| 662 prior = priorTest; | 786 prior = priorTest; |
| 663 priorOpp = opp; | 787 priorOpp = opp; |
| 664 break; | 788 break; |
| 665 } | 789 } |
| 666 } | 790 } |
| 667 priorTest = priorTest->prev(); | 791 priorTest = priorTest->prev(); |
| 668 } | 792 } |
| 669 if (!priorOpp) { | 793 if (!priorOpp) { |
| 670 continue; | 794 continue; |
| 671 } | 795 } |
| 796 if (priorPtT == ptT) { | |
| 797 continue; | |
| 798 } | |
| 672 const SkOpPtT* oppStart = prior->ptT(); | 799 const SkOpPtT* oppStart = prior->ptT(); |
| 673 const SkOpPtT* oppEnd = spanBase->ptT(); | 800 const SkOpPtT* oppEnd = spanBase->ptT(); |
| 674 bool swapped = priorPtT->fT > ptT->fT; | 801 bool swapped = priorPtT->fT > ptT->fT; |
| 675 if (swapped) { | 802 if (swapped) { |
| 676 SkTSwap(priorPtT, ptT); | 803 SkTSwap(priorPtT, ptT); |
| 677 SkTSwap(oppStart, oppEnd); | 804 SkTSwap(oppStart, oppEnd); |
| 678 } | 805 } |
| 679 bool flipped = oppStart->fT > oppEnd->fT; | 806 const SkOpCoincidence* coincidence = this->globalState()->coincidenc e(); |
| 680 bool coincident = false; | 807 const SkOpPtT* rootPriorPtT = priorPtT->span()->ptT(); |
| 681 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped) ) { | 808 const SkOpPtT* rootPtT = ptT->span()->ptT(); |
| 809 const SkOpPtT* rootOppStart = oppStart->span()->ptT(); | |
| 810 const SkOpPtT* rootOppEnd = oppEnd->span()->ptT(); | |
| 811 if (coincidence->contains(rootPriorPtT, rootPtT, rootOppStart, rootO ppEnd)) { | |
| 682 goto swapBack; | 812 goto swapBack; |
| 683 } | 813 } |
| 684 if (opp->verb() == SkPath::kLine_Verb) { | 814 if (testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) { |
| 685 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppSta rt->fPt) || | 815 // mark coincidence |
| 686 SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt) ) && | 816 #if DEBUG_COINCIDENCE |
| 687 (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) | | | 817 // SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\ n", __FUNCTION__, |
|
herb_g
2016/07/18 15:13:39
Remove commented out code.
caryclark
2016/07/18 15:55:49
See above
| |
| 688 SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt)); | 818 // rootPriorPtT->debugID(), rootPtT->debugID(), rootOppS tart->debugID(), |
| 689 } | 819 // rootOppEnd->debugID()); |
| 690 if (!coincident) { | 820 #endif |
| 691 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000); | |
| 692 } | |
| 693 if (coincident) { | |
| 694 log->record(kMissingCoin_Glitch, id, priorPtT, ptT, oppStart, op pEnd); | 821 log->record(kMissingCoin_Glitch, id, priorPtT, ptT, oppStart, op pEnd); |
| 822 // coincidences->add(rootPriorPtT, rootPtT, rootOppStart, root OppEnd); | |
| 823 // } | |
| 824 #if DEBUG_COINCIDENCE | |
| 825 // SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOpp Start, rootOppEnd) | |
| 826 #endif | |
| 827 // result = true; | |
| 695 } | 828 } |
| 696 swapBack: | 829 swapBack: |
| 697 if (swapped) { | 830 if (swapped) { |
| 698 SkTSwap(priorPtT, ptT); | 831 SkTSwap(priorPtT, ptT); |
| 699 } | 832 } |
| 700 } | 833 } |
| 701 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next( ))); | 834 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next( ))); |
| 835 DebugClearVisited(&fHead); | |
| 836 return; | |
| 702 } | 837 } |
| 703 | 838 |
| 839 // commented-out lines keep this in sync with moveMultiples() | |
| 840 // if a span has more than one intersection, merge the other segments' span as n eeded | |
| 704 void SkOpSegment::debugMoveMultiples(const char* id, SkPathOpsDebug::GlitchLog* glitches) const { | 841 void SkOpSegment::debugMoveMultiples(const char* id, SkPathOpsDebug::GlitchLog* glitches) const { |
| 842 debugValidate(); | |
| 705 const SkOpSpanBase* test = &fHead; | 843 const SkOpSpanBase* test = &fHead; |
| 706 do { | 844 do { |
| 707 int addCount = test->spanAddsCount(); | 845 int addCount = test->spanAddsCount(); |
| 708 SkASSERT(addCount >= 1); | 846 SkASSERT(addCount >= 1); |
| 709 if (addCount == 1) { | 847 if (addCount == 1) { |
| 710 continue; | 848 continue; |
| 711 } | 849 } |
| 712 const SkOpPtT* startPtT = test->ptT(); | 850 const SkOpPtT* startPtT = test->ptT(); |
| 713 const SkOpPtT* testPtT = startPtT; | 851 const SkOpPtT* testPtT = startPtT; |
| 714 do { // iterate through all spans associated with start | 852 do { // iterate through all spans associated with start |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 770 goto tryNextSpan; | 908 goto tryNextSpan; |
| 771 } | 909 } |
| 772 const SkOpPtT* matchPtT = startPtT; | 910 const SkOpPtT* matchPtT = startPtT; |
| 773 do { | 911 do { |
| 774 if (matchPtT->segment() == oppPtTSegment) { | 912 if (matchPtT->segment() == oppPtTSegment) { |
| 775 goto foundMatch; | 913 goto foundMatch; |
| 776 } | 914 } |
| 777 } while ((matchPtT = matchPtT->next()) != startPtT); | 915 } while ((matchPtT = matchPtT->next()) != startPtT); |
| 778 goto tryNextSpan; | 916 goto tryNextSpan; |
| 779 foundMatch: // merge oppTest and oppSpan | 917 foundMatch: // merge oppTest and oppSpan |
| 918 oppSegment->debugValidate(); | |
| 780 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment- >fHead) { | 919 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment- >fHead) { |
| 781 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse | 920 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse |
| 782 SkASSERT(oppSpan != &oppSegment->fTail); | 921 SkASSERT(oppSpan != &oppSegment->fTail); |
| 783 glitches->record(kMoveMultiple_Glitch, id, oppTest, oppS pan); | 922 glitches->record(kMoveMultiple_Glitch, id, oppTest, oppS pan); |
| 784 } else { | 923 } else { |
| 785 glitches->record(kMoveMultiple_Glitch, id, oppSpan, oppT est); | 924 glitches->record(kMoveMultiple_Glitch, id, oppSpan, oppT est); |
| 786 } | 925 } |
| 926 oppSegment->debugValidate(); | |
| 787 goto checkNextSpan; | 927 goto checkNextSpan; |
| 788 } | 928 } |
| 789 tryNextSpan: | 929 tryNextSpan: |
| 790 ; | 930 ; |
| 791 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()) ); | 931 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()) ); |
| 792 } while ((testPtT = testPtT->next()) != startPtT); | 932 } while ((testPtT = testPtT->next()) != startPtT); |
| 793 checkNextSpan: | 933 checkNextSpan: |
| 794 ; | 934 ; |
| 795 } while ((test = test->final() ? nullptr : test->upCast()->next())); | 935 } while ((test = test->final() ? nullptr : test->upCast()->next())); |
| 936 debugValidate(); | |
| 937 return; | |
| 796 } | 938 } |
| 797 | 939 |
| 940 // commented-out lines keep this in sync with moveNearby() | |
| 941 // Move nearby t values and pts so they all hang off the same span. Alignment ha ppens later. | |
| 798 void SkOpSegment::debugMoveNearby(const char* id, SkPathOpsDebug::GlitchLog* gli tches) const { | 942 void SkOpSegment::debugMoveNearby(const char* id, SkPathOpsDebug::GlitchLog* gli tches) const { |
| 799 const SkOpSpanBase* spanS = &fHead; | 943 debugValidate(); |
| 944 // release undeleted spans pointing to this seg that are linked to the prima ry span | |
| 945 const SkOpSpanBase* spanBase = &fHead; | |
| 800 do { | 946 do { |
| 801 const SkOpSpanBase* test = spanS->upCast()->next(); | 947 const SkOpPtT* ptT = spanBase->ptT(); |
| 802 const SkOpSpanBase* next; | 948 const SkOpPtT* headPtT = ptT; |
| 803 if (spanS->contains(test)) { | 949 while ((ptT = ptT->next()) != headPtT) { |
| 804 if (!test->final()) { | 950 const SkOpSpanBase* test = ptT->span(); |
| 805 glitches->record(kUndetachedSpan_Glitch, id, test, spanS); | 951 if (ptT->segment() == this && !ptT->deleted() && test != spanBase |
| 806 } else if (spanS != &fHead) { | 952 && test->ptT() == ptT) { |
| 807 glitches->record(kUndetachedSpan_Glitch, id, spanS, test); | 953 if (test->final()) { |
| 954 if (spanBase == &fHead) { | |
| 955 glitches->record(kMoveNearbyClearAll_Glitch, id, this); | |
| 956 // return; | |
|
herb_g
2016/07/18 15:13:39
Remove commented out code.
caryclark
2016/07/18 15:55:49
See comment above.
| |
| 957 } | |
| 958 glitches->record(kMoveNearbyReleaseFinal_Glitch, id, spanBas e, ptT); | |
| 959 } else if (test->prev()) { | |
| 960 glitches->record(kMoveNearbyRelease_Glitch, id, test, headPt T); | |
| 961 } | |
| 962 // break; | |
| 808 } | 963 } |
| 809 } | 964 } |
| 810 do { // iterate through all spans associated with start | 965 spanBase = spanBase->upCast()->next(); |
| 811 const SkOpPtT* startBase = spanS->ptT(); | 966 } while (!spanBase->final()); |
| 812 next = test->final() ? nullptr : test->upCast()->next(); | 967 |
| 813 do { | 968 // This loop looks for adjacent spans which are near by |
| 814 const SkOpPtT* testBase = test->ptT(); | 969 spanBase = &fHead; |
| 815 do { | 970 do { // iterate through all spans associated with start |
| 816 if (startBase == testBase) { | 971 const SkOpSpanBase* test = spanBase->upCast()->next(); |
| 817 goto checkNextSpan; | 972 if (this->spansNearby(spanBase, test)) { |
| 818 } | 973 if (test->final()) { |
| 819 if (testBase->duplicate()) { | 974 if (spanBase->prev()) { |
| 820 continue; | 975 glitches->record(kMoveNearbyMergeFinal_Glitch, id, test); |
| 821 } | 976 } else { |
| 822 if (this->match(startBase, testBase->segment(), testBase->fT , testBase->fPt)) { | 977 glitches->record(kMoveNearbyClearAll2_Glitch, id, this); |
| 823 if (test == &this->fTail) { | 978 // return |
| 824 if (spanS == &fHead) { | 979 } |
| 825 glitches->record(kCollapsedSpan_Glitch, id, span S); | 980 } else { |
| 826 } else { | 981 glitches->record(kMoveNearbyMerge_Glitch, id, spanBase); |
| 827 glitches->record(kUnmergedSpan_Glitch, id, &this ->fTail, spanS); | 982 } |
| 828 } | 983 } |
| 829 } else { | 984 spanBase = test; |
| 830 glitches->record(kUnmergedSpan_Glitch, id, spanS, te st); | 985 } while (!spanBase->final()); |
| 831 goto checkNextSpan; | 986 debugValidate(); |
| 832 } | |
| 833 } | |
| 834 } while ((testBase = testBase->next()) != test->ptT()); | |
| 835 } while ((startBase = startBase->next()) != spanS->ptT()); | |
| 836 checkNextSpan: | |
| 837 ; | |
| 838 } while ((test = next)); | |
| 839 spanS = spanS->upCast()->next(); | |
| 840 } while (!spanS->final()); | |
| 841 } | 987 } |
| 842 #endif | 988 #endif |
| 843 | 989 |
| 844 void SkOpSegment::debugReset() { | 990 void SkOpSegment::debugReset() { |
| 845 this->init(this->fPts, this->fWeight, this->contour(), this->verb()); | 991 this->init(this->fPts, this->fWeight, this->contour(), this->verb()); |
| 846 } | 992 } |
| 847 | 993 |
| 848 #if DEBUG_ACTIVE_SPANS | 994 #if DEBUG_ACTIVE_SPANS |
| 849 void SkOpSegment::debugShowActiveSpans() const { | 995 void SkOpSegment::debugShowActiveSpans() const { |
| 850 debugValidate(); | 996 debugValidate(); |
| 851 if (done()) { | 997 if (done()) { |
| 852 return; | 998 return; |
| 853 } | 999 } |
| 854 int lastId = -1; | 1000 int lastId = -1; |
| 855 double lastT = -1; | 1001 double lastT = -1; |
| 856 const SkOpSpan* span = &fHead; | 1002 const SkOpSpan* span = &fHead; |
| 857 do { | 1003 do { |
| 858 if (span->done()) { | 1004 if (span->done()) { |
| 859 continue; | 1005 continue; |
| 860 } | 1006 } |
| 861 if (lastId == this->debugID() && lastT == span->t()) { | 1007 if (lastId == this->debugID() && lastT == span->t()) { |
| 862 continue; | 1008 continue; |
| 863 } | 1009 } |
| 864 lastId = this->debugID(); | 1010 lastId = this->debugID(); |
| 865 lastT = span->t(); | 1011 lastT = span->t(); |
| 866 SkDebugf("%s id=%d", __FUNCTION__, this->debugID()); | 1012 SkDebugf("%s id=%d", __FUNCTION__, this->debugID()); |
| 867 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 1013 // since endpoints may have be adjusted, show actual computed curves |
| 1014 SkDCurve curvePart; | |
| 1015 this->subDivide(span, span->next(), &curvePart); | |
| 1016 const SkDPoint* pts = curvePart.fCubic.fPts; | |
| 1017 SkDebugf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY); | |
| 868 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | 1018 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 869 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | 1019 SkDebugf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY); |
| 870 } | 1020 } |
| 871 if (SkPath::kConic_Verb == fVerb) { | 1021 if (SkPath::kConic_Verb == fVerb) { |
| 872 SkDebugf(" %1.9gf", fWeight); | 1022 SkDebugf(" %1.9gf", curvePart.fConic.fWeight); |
| 873 } | 1023 } |
| 874 const SkOpPtT* ptT = span->ptT(); | 1024 SkDebugf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t()); |
| 875 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY); | |
| 876 SkDebugf(" tEnd=%1.9g", span->next()->t()); | |
| 877 if (span->windSum() == SK_MinS32) { | 1025 if (span->windSum() == SK_MinS32) { |
| 878 SkDebugf(" windSum=?"); | 1026 SkDebugf(" windSum=?"); |
| 879 } else { | 1027 } else { |
| 880 SkDebugf(" windSum=%d", span->windSum()); | 1028 SkDebugf(" windSum=%d", span->windSum()); |
| 881 } | 1029 } |
| 882 if (span->oppValue() && span->oppSum() == SK_MinS32) { | 1030 if (span->oppValue() && span->oppSum() == SK_MinS32) { |
| 883 SkDebugf(" oppSum=?"); | 1031 SkDebugf(" oppSum=?"); |
| 884 } else if (span->oppValue() || span->oppSum() != SK_MinS32) { | 1032 } else if (span->oppValue() || span->oppSum() != SK_MinS32) { |
| 885 SkDebugf(" oppSum=%d", span->oppSum()); | 1033 SkDebugf(" oppSum=%d", span->oppSum()); |
| 886 } | 1034 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 951 SkDebugf("%d", span->windSum()); | 1099 SkDebugf("%d", span->windSum()); |
| 952 } | 1100 } |
| 953 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue()) ; | 1101 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue()) ; |
| 954 } | 1102 } |
| 955 | 1103 |
| 956 #endif | 1104 #endif |
| 957 | 1105 |
| 958 // loop looking for a pair of angle parts that are too close to be sorted | 1106 // loop looking for a pair of angle parts that are too close to be sorted |
| 959 /* This is called after other more simple intersection and angle sorting tests h ave been exhausted. | 1107 /* This is called after other more simple intersection and angle sorting tests h ave been exhausted. |
| 960 This should be rarely called -- the test below is thorough and time consuming . | 1108 This should be rarely called -- the test below is thorough and time consuming . |
| 961 This checks the distance between start points; the distance between | 1109 This checks the distance between start points; the distance between |
| 962 */ | 1110 */ |
| 963 #if DEBUG_ANGLE | 1111 #if DEBUG_ANGLE |
| 964 void SkOpAngle::debugCheckNearCoincidence() const { | 1112 void SkOpAngle::debugCheckNearCoincidence() const { |
| 965 const SkOpAngle* test = this; | 1113 const SkOpAngle* test = this; |
| 966 do { | 1114 do { |
| 967 const SkOpSegment* testSegment = test->segment(); | 1115 const SkOpSegment* testSegment = test->segment(); |
| 968 double testStartT = test->start()->t(); | 1116 double testStartT = test->start()->t(); |
| 969 SkDPoint testStartPt = testSegment->dPtAtT(testStartT); | 1117 SkDPoint testStartPt = testSegment->dPtAtT(testStartT); |
| 970 double testEndT = test->end()->t(); | 1118 double testEndT = test->end()->t(); |
| 971 SkDPoint testEndPt = testSegment->dPtAtT(testEndT); | 1119 SkDPoint testEndPt = testSegment->dPtAtT(testEndT); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 989 SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq); | 1137 SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq); |
| 990 SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq); | 1138 SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq); |
| 991 SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq); | 1139 SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq); |
| 992 SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq); | 1140 SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq); |
| 993 SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT); | 1141 SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT); |
| 994 double nextLenSq = nextStartPt.distanceSquared(nextEndPt); | 1142 double nextLenSq = nextStartPt.distanceSquared(nextEndPt); |
| 995 SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq); | 1143 SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq); |
| 996 SkDebugf("\n"); | 1144 SkDebugf("\n"); |
| 997 } | 1145 } |
| 998 test = test->fNext; | 1146 test = test->fNext; |
| 999 } while (test->fNext != this); | 1147 } while (test->fNext != this); |
| 1000 } | 1148 } |
| 1001 #endif | 1149 #endif |
| 1002 | 1150 |
| 1003 #if DEBUG_ANGLE | 1151 #if DEBUG_ANGLE |
| 1004 SkString SkOpAngle::debugPart() const { | 1152 SkString SkOpAngle::debugPart() const { |
| 1005 SkString result; | 1153 SkString result; |
| 1006 switch (this->segment()->verb()) { | 1154 switch (this->segment()->verb()) { |
| 1007 case SkPath::kLine_Verb: | 1155 case SkPath::kLine_Verb: |
| 1008 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart), | 1156 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart), |
| 1009 this->segment()->debugID()); | 1157 this->segment()->debugID()); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1039 } while (next && next != first); | 1187 } while (next && next != first); |
| 1040 next = first; | 1188 next = first; |
| 1041 do { | 1189 do { |
| 1042 next->debugValidate(); | 1190 next->debugValidate(); |
| 1043 next = next->fNext; | 1191 next = next->fNext; |
| 1044 } while (next && next != first); | 1192 } while (next && next != first); |
| 1045 } | 1193 } |
| 1046 #endif | 1194 #endif |
| 1047 | 1195 |
| 1048 void SkOpAngle::debugValidate() const { | 1196 void SkOpAngle::debugValidate() const { |
| 1197 #if DEBUG_COINCIDENCE | |
| 1198 if (this->globalState()->debugCheckHealth()) { | |
| 1199 return; | |
| 1200 } | |
| 1201 #endif | |
| 1049 #if DEBUG_VALIDATE | 1202 #if DEBUG_VALIDATE |
| 1050 const SkOpAngle* first = this; | 1203 const SkOpAngle* first = this; |
| 1051 const SkOpAngle* next = this; | 1204 const SkOpAngle* next = this; |
| 1052 int wind = 0; | 1205 int wind = 0; |
| 1053 int opp = 0; | 1206 int opp = 0; |
| 1054 int lastXor = -1; | 1207 int lastXor = -1; |
| 1055 int lastOppXor = -1; | 1208 int lastOppXor = -1; |
| 1056 do { | 1209 do { |
| 1057 if (next->unorderable()) { | 1210 if (next->unorderable()) { |
| 1058 return; | 1211 return; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1101 break; | 1254 break; |
| 1102 } | 1255 } |
| 1103 SkASSERT_RELEASE(!angles.contains(next)); | 1256 SkASSERT_RELEASE(!angles.contains(next)); |
| 1104 if (!next) { | 1257 if (!next) { |
| 1105 return; | 1258 return; |
| 1106 } | 1259 } |
| 1107 } while (true); | 1260 } while (true); |
| 1108 #endif | 1261 #endif |
| 1109 } | 1262 } |
| 1110 | 1263 |
| 1111 | 1264 #ifdef SK_DEBUG |
| 1112 #if DEBUG_COINCIDENCE | 1265 void SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpa nBase* over, |
| 1266 const SkOpGlobalState* debugState) const { | |
| 1267 SkASSERT(coinPtTEnd()->span() == over || !debugState->debugRunFail()); | |
| 1268 SkASSERT(oppPtTEnd()->span() == outer || !debugState->debugRunFail()); | |
| 1269 } | |
| 1270 #endif | |
| 1271 | |
| 1272 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1273 /* Commented-out lines keep this in sync with expand */ | |
| 1274 bool SkCoincidentSpans::debugExpand(const char* id, SkPathOpsDebug::GlitchLog* l og) const { | |
| 1275 bool expanded = false; | |
| 1276 const SkOpSegment* segment = coinPtTStart()->segment(); | |
| 1277 const SkOpSegment* oppSegment = oppPtTStart()->segment(); | |
| 1278 do { | |
| 1279 const SkOpSpan* start = coinPtTStart()->span()->upCast(); | |
| 1280 const SkOpSpan* prev = start->prev(); | |
| 1281 const SkOpPtT* oppPtT; | |
| 1282 if (!prev || !(oppPtT = prev->contains(oppSegment))) { | |
| 1283 break; | |
| 1284 } | |
| 1285 double midT = (prev->t() + start->t()) / 2; | |
| 1286 if (!segment->isClose(midT, oppSegment)) { | |
| 1287 break; | |
| 1288 } | |
| 1289 if (log) log->record(kExpandCoin_Glitch, id, this, prev->ptT(), oppPtT); | |
| 1290 expanded = true; | |
| 1291 } while (false); // actual continues while expansion is possible | |
| 1292 do { | |
| 1293 const SkOpSpanBase* end = coinPtTEnd()->span(); | |
| 1294 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); | |
| 1295 const SkOpPtT* oppPtT; | |
| 1296 if (!next || !(oppPtT = next->contains(oppSegment))) { | |
| 1297 break; | |
| 1298 } | |
| 1299 double midT = (end->t() + next->t()) / 2; | |
| 1300 if (!segment->isClose(midT, oppSegment)) { | |
| 1301 break; | |
| 1302 } | |
| 1303 if (log) log->record(kExpandCoin_Glitch, id, this, next->ptT(), oppPtT); | |
| 1304 expanded = true; | |
| 1305 } while (false); // actual continues while expansion is possible | |
| 1306 return expanded; | |
| 1307 } | |
| 1308 | |
| 1309 #define FAIL_IF(cond) do { if (cond) log->record(kAddExpandedFail_Glitch, id, c oin); } while (false) | |
| 1310 | |
| 1311 /* Commented-out lines keep this in sync with addExpanded */ | |
| 1312 // for each coincident pair, match the spans | |
| 1313 // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span | |
| 1113 void SkOpCoincidence::debugAddExpanded(const char* id, SkPathOpsDebug::GlitchLog * log) const { | 1314 void SkOpCoincidence::debugAddExpanded(const char* id, SkPathOpsDebug::GlitchLog * log) const { |
| 1114 // for each coincident pair, match the spans | |
| 1115 // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span | |
| 1116 const SkCoincidentSpans* coin = this->fHead; | 1315 const SkCoincidentSpans* coin = this->fHead; |
| 1117 if (!coin) { | 1316 if (!coin) { |
| 1118 coin = this->fTop; | 1317 return; |
| 1119 } | 1318 } |
| 1120 if (!coin) { | 1319 do { |
| 1121 return; | 1320 const SkOpPtT* startPtT = coin->coinPtTStart(); |
| 1122 } | 1321 const SkOpPtT* oStartPtT = coin->oppPtTStart(); |
| 1123 do { | |
| 1124 const SkOpPtT* startPtT = coin->fCoinPtTStart; | |
| 1125 const SkOpPtT* oStartPtT = coin->fOppPtTStart; | |
| 1126 SkASSERT(startPtT->contains(oStartPtT)); | 1322 SkASSERT(startPtT->contains(oStartPtT)); |
| 1127 SkASSERT(coin->fCoinPtTEnd->contains(coin->fOppPtTEnd)); | 1323 SkASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd())); |
| 1128 const SkOpSpanBase* start = startPtT->span(); | 1324 const SkOpSpanBase* start = startPtT->span(); |
| 1129 const SkOpSpanBase* oStart = oStartPtT->span(); | 1325 const SkOpSpanBase* oStart = oStartPtT->span(); |
| 1130 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); | 1326 const SkOpSpanBase* end = coin->coinPtTEnd()->span(); |
| 1131 const SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); | 1327 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span(); |
| 1328 FAIL_IF(oEnd->deleted()); | |
| 1132 const SkOpSpanBase* test = start->upCast()->next(); | 1329 const SkOpSpanBase* test = start->upCast()->next(); |
| 1133 const SkOpSpanBase* oTest = coin->fFlipped ? oStart->prev() : oStart->up Cast()->next(); | 1330 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->u pCast()->next(); |
| 1331 if (!oTest) { | |
| 1332 return; | |
| 1333 } | |
| 1134 while (test != end || oTest != oEnd) { | 1334 while (test != end || oTest != oEnd) { |
| 1135 bool bumpTest = true; | 1335 if (!test->ptT()->contains(oTest->segment()) |
| 1136 bool bumpOTest = true; | 1336 || !oTest->ptT()->contains(start->segment())) { |
| 1137 if (!test->ptT()->contains(oTest->ptT())) { | |
| 1138 // use t ranges to guess which one is missing | 1337 // use t ranges to guess which one is missing |
| 1139 double startRange = coin->fCoinPtTEnd->fT - startPtT->fT; | 1338 double startRange = coin->coinPtTEnd()->fT - startPtT->fT; |
| 1339 FAIL_IF(!startRange); | |
| 1140 double startPart = (test->t() - startPtT->fT) / startRange; | 1340 double startPart = (test->t() - startPtT->fT) / startRange; |
| 1141 double oStartRange = coin->fOppPtTEnd->fT - oStartPtT->fT; | 1341 double oStartRange = coin->oppPtTEnd()->fT - oStartPtT->fT; |
| 1342 FAIL_IF(!oStartRange); | |
| 1142 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; | 1343 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; |
| 1143 if (startPart == oStartPart) { | 1344 FAIL_IF(startPart == oStartPart); |
| 1144 // data is corrupt | 1345 bool startOver = false; |
| 1145 log->record(kAddCorruptCoin_Glitch, id, start, oStart); | 1346 if (startPart < oStartPart) |
| 1146 break; | 1347 log->record(kAddExpandedCoin_Glitch, id, // strange deb ug formatting lines up with original |
| 1147 } | 1348 oStartPtT->fT + oStartRange * startPart, test); |
| 1148 if (startPart < oStartPart) { | 1349 else log->record(kAddExpandedCoin_Glitch, id, |
| 1149 double newT = oStartPtT->fT + oStartRange * startPart; | 1350 startPtT->fT + startRange * oStartPart, oTest); |
| 1150 log->record(kAddExpandedCoin_Glitch, id, oStart, newT, test- >pt()); | 1351 if (false) { |
| 1151 bumpOTest = false; | 1352 SkASSERT(0); |
| 1152 } else { | 1353 return; |
| 1153 double newT = startPtT->fT + startRange * oStartPart; | 1354 } |
| 1154 log->record(kAddExpandedCoin_Glitch, id, start, newT, oTest- >pt()); | 1355 if (startOver) { |
| 1155 bumpTest = false; | 1356 test = start; |
| 1156 } | 1357 oTest = oStart; |
| 1157 } | 1358 } |
| 1158 if (bumpTest && test != end) { | 1359 } |
| 1360 if (test != end) { | |
| 1159 test = test->upCast()->next(); | 1361 test = test->upCast()->next(); |
| 1160 } | 1362 } |
| 1161 if (bumpOTest && oTest != oEnd) { | 1363 if (oTest != oEnd) { |
| 1162 oTest = coin->fFlipped ? oTest->prev() : oTest->upCast()->next() ; | 1364 oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next( ); |
| 1163 } | 1365 if (!oTest) { |
| 1164 } | 1366 return; |
| 1165 } while ((coin = coin->fNext)); | 1367 } |
| 1166 } | 1368 } |
| 1167 | 1369 } |
| 1168 static void t_range(const SkOpPtT* overS, const SkOpPtT* overE, double tStart, d ouble tEnd, | 1370 } while ((coin = coin->next())); |
| 1169 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, double* coinTs, double* coinTe) { | 1371 return; |
| 1170 double denom = overE->fT - overS->fT; | 1372 } |
| 1171 double start = 0 < denom ? tStart : tEnd; | 1373 |
| 1172 double end = 0 < denom ? tEnd : tStart; | 1374 /* Commented-out lines keep this in sync with addIfMissing() */ |
| 1173 double sRatio = (start - overS->fT) / denom; | 1375 void SkOpCoincidence::debugAddIfMissing(const SkCoincidentSpans* outer, const Sk OpPtT* over1s, |
| 1174 double eRatio = (end - overS->fT) / denom; | 1376 const SkOpPtT* over1e, const char* id, SkPathOpsDebug::GlitchLog* lo g) const { |
| 1175 *coinTs = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * sRatio; | 1377 // SkASSERT(fTop); |
| 1176 *coinTe = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * eRatio; | 1378 if (fTop && alreadyAdded(fTop, outer, over1s, over1e)) { // in debug, fTop may be null |
| 1177 } | 1379 return; |
| 1178 | 1380 } |
| 1179 bool SkOpCoincidence::debugAddIfMissing(const SkCoincidentSpans* outer, const Sk OpPtT* over1s, | 1381 if (fHead && alreadyAdded(fHead, outer, over1s, over1e)) { |
| 1180 const SkOpPtT* over1e) const { | 1382 return; |
| 1181 const SkCoincidentSpans* check = this->fTop; | 1383 } |
| 1182 while (check) { | 1384 log->record(kAddIfMissingCoin_Glitch, id, outer->coinPtTStart(), outer->coin PtTEnd(), over1s, over1e); |
| 1183 if (check->fCoinPtTStart->span() == over1s->span() | 1385 this->debugValidate(); |
| 1184 && check->fOppPtTStart->span() == outer->fOppPtTStart->span()) { | 1386 return; |
| 1185 SkASSERT(check->fCoinPtTEnd->span() == over1e->span() | 1387 } |
| 1186 || !fDebugState->debugRunFail()); | 1388 |
| 1187 SkASSERT(check->fOppPtTEnd->span() == outer->fOppPtTEnd->span() | 1389 /* Commented-out lines keep this in sync addIfMissing() */ |
| 1188 || !fDebugState->debugRunFail()); | 1390 void SkOpCoincidence::debugAddIfMissing(const SkOpPtT* over1s, const SkOpPtT* ov er1e, |
| 1189 return false; | 1391 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStart, double tEnd , |
| 1190 } | 1392 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, |
| 1191 if (check->fCoinPtTStart->span() == outer->fCoinPtTStart->span() | 1393 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, const char* id, Sk PathOpsDebug::GlitchLog* log) const { |
| 1192 && check->fOppPtTStart->span() == over1s->span()) { | |
| 1193 SkASSERT(check->fCoinPtTEnd->span() == outer->fCoinPtTEnd->span() | |
| 1194 || !fDebugState->debugRunFail()); | |
| 1195 SkASSERT(check->fOppPtTEnd->span() == over1e->span() | |
| 1196 || !fDebugState->debugRunFail()); | |
| 1197 return false; | |
| 1198 } | |
| 1199 check = check->fNext; | |
| 1200 } | |
| 1201 return true; | |
| 1202 } | |
| 1203 | |
| 1204 bool SkOpCoincidence::debugAddIfMissing(const SkOpPtT* over1s, const SkOpPtT* ov er1e, | |
| 1205 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStar t, double tEnd, | |
| 1206 SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, | |
| 1207 SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const { | |
| 1208 double coinTs, coinTe, oppTs, oppTe; | 1394 double coinTs, coinTe, oppTs, oppTe; |
| 1209 t_range(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &co inTe); | 1395 TRange(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &coi nTe); |
| 1210 t_range(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe ); | 1396 TRange(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe) ; |
| 1397 bool swap = coinTs > coinTe; | |
| 1398 if (swap) { | |
| 1399 SkTSwap(coinTs, coinTe); | |
| 1400 } | |
| 1401 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) { | |
| 1402 SkTSwap(oppTs, oppTe); | |
| 1403 } | |
| 1404 if (swap) { | |
| 1405 SkTSwap(oppTs, oppTe); | |
| 1406 } | |
| 1211 const SkOpSegment* coinSeg = coinPtTStart->segment(); | 1407 const SkOpSegment* coinSeg = coinPtTStart->segment(); |
| 1212 const SkOpSegment* oppSeg = oppPtTStart->segment(); | 1408 const SkOpSegment* oppSeg = oppPtTStart->segment(); |
| 1213 SkASSERT(coinSeg != oppSeg); | 1409 if (coinSeg == oppSeg) { |
| 1214 const SkCoincidentSpans* check = this->fTop; | 1410 return; |
| 1215 ; | 1411 } |
| 1216 while (check) { | 1412 return this->debugAddOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe , id, log); |
| 1217 const SkOpSegment* checkCoinSeg = check->fCoinPtTStart->segment(); | 1413 } |
| 1218 const SkOpSegment* checkOppSeg; | 1414 |
| 1219 if (checkCoinSeg != coinSeg && checkCoinSeg != oppSeg) { | 1415 /* Commented-out lines keep this in sync addOrOverlap() */ |
| 1220 goto next; | 1416 void SkOpCoincidence::debugAddOrOverlap(const SkOpSegment* coinSeg, const SkOpSe gment* oppSeg, |
| 1221 } | 1417 double coinTs, double coinTe, double oppTs, double oppTe, const char* id , SkPathOpsDebug::GlitchLog* log) const { |
| 1222 checkOppSeg = check->fOppPtTStart->segment(); | 1418 SkTDArray<SkCoincidentSpans*> overlaps; |
| 1223 if (checkOppSeg != coinSeg && checkOppSeg != oppSeg) { | 1419 SkASSERT(!fTop); // this is (correctly) reversed in addifMissing() |
| 1224 goto next; | 1420 if (fTop && !this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs , oppTe, &overlaps)) { |
| 1225 } | 1421 return; |
| 1226 { | 1422 } |
| 1227 int cTs = coinTs; | 1423 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs, |
| 1228 int cTe = coinTe; | 1424 coinTe, oppTs, oppTe, &overlaps)) { |
| 1229 int oTs = oppTs; | 1425 return; |
| 1230 int oTe = oppTe; | 1426 } |
| 1231 if (checkCoinSeg != coinSeg) { | 1427 const SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr; |
| 1232 SkASSERT(checkOppSeg != oppSeg); | 1428 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing |
| 1233 SkTSwap(cTs, oTs); | 1429 const SkCoincidentSpans* test = overlaps[index]; |
| 1234 SkTSwap(cTe, oTe); | 1430 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) { |
| 1235 } | 1431 log->record(kAddOrOverlap_Glitch, id, overlap, test->coinPtTStart()) ; |
| 1236 int tweenCount = (int) between(check->fCoinPtTStart->fT, cTs, check- >fCoinPtTEnd->fT) | 1432 } |
| 1237 + (int) between(check->fCoinPtTStart->fT, cTe, check- >fCoinPtTEnd->fT) | 1433 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) { |
| 1238 + (int) between(check->fOppPtTStart->fT, oTs, check-> fOppPtTEnd->fT) | 1434 log->record(kAddOrOverlap_Glitch, id, overlap, test->coinPtTEnd()); |
| 1239 + (int) between(check->fOppPtTStart->fT, oTe, check-> fOppPtTEnd->fT); | 1435 } |
| 1240 // SkASSERT(tweenCount == 0 || tweenCount == 4); | 1436 if (overlap->flipped() |
| 1241 if (tweenCount) { | 1437 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT |
| 1242 return true; | 1438 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) { |
| 1243 } | 1439 log->record(kAddOrOverlap_Glitch, id, overlap, test->oppPtTStart()); |
| 1244 } | 1440 } |
| 1245 next: | 1441 if (overlap->flipped() |
| 1246 check = check->fNext; | 1442 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT |
| 1247 } | 1443 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) { |
| 1248 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) { | 1444 log->record(kAddOrOverlap_Glitch, id, overlap, test->oppPtTEnd()); |
| 1249 SkTSwap(oppTs, oppTe); | 1445 } |
| 1250 } | 1446 if (!fHead) { |
| 1251 if (coinTs > coinTe) { | 1447 SkAssertResult(true); |
| 1252 SkTSwap(coinTs, coinTe); | 1448 } |
| 1253 SkTSwap(oppTs, oppTe); | 1449 } |
| 1254 } | 1450 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg); |
| 1255 bool cs = coinSeg->debugAddMissing(coinTs, oppSeg); | 1451 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg); |
| 1256 bool ce = coinSeg->debugAddMissing(coinTe, oppSeg); | 1452 if (overlap && cs && ce && overlap->contains(cs, ce)) { |
| 1257 if (cs == ce) { | 1453 return; |
| 1258 return false; | 1454 } |
| 1259 } | 1455 SkASSERT(cs != ce || !cs); |
| 1260 return true; | 1456 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg); |
| 1261 } | 1457 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg); |
| 1262 | 1458 if (overlap && os && oe && overlap->contains(os, oe)) { |
| 1459 return; | |
| 1460 } | |
| 1461 SkASSERT(true || !cs || !cs->deleted()); | |
| 1462 SkASSERT(true || !os || !os->deleted()); | |
| 1463 SkASSERT(true || !ce || !ce->deleted()); | |
| 1464 SkASSERT(true || !oe || !oe->deleted()); | |
| 1465 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullp tr; | |
| 1466 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullp tr; | |
| 1467 if (csExisting && csExisting == ceExisting) { | |
| 1468 return; | |
| 1469 } | |
| 1470 if (csExisting && (csExisting == ce || csExisting->contains(ceExisting ? ceE xisting : ce))) { | |
| 1471 return; | |
| 1472 } | |
| 1473 if (ceExisting && (ceExisting == cs || ceExisting->contains(csExisting ? csE xisting : cs))) { | |
| 1474 return; | |
| 1475 } | |
| 1476 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr ; | |
| 1477 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr ; | |
| 1478 if (osExisting && osExisting == oeExisting) { | |
| 1479 return; | |
| 1480 } | |
| 1481 if (osExisting && (osExisting == oe || osExisting->contains(oeExisting ? oeE xisting : oe))) { | |
| 1482 return; | |
| 1483 } | |
| 1484 if (oeExisting && (oeExisting == os || oeExisting->contains(osExisting ? osE xisting : os))) { | |
| 1485 return; | |
| 1486 } | |
| 1487 bool csDeleted = false, osDeleted = false, ceDeleted = false, oeDeleted = f alse; | |
| 1488 this->debugValidate(); | |
| 1489 if (!cs || !os) { | |
| 1490 if (!cs) | |
| 1491 cs = coinSeg->debugAddT(coinTs, SkOpSegment::kNoAliasMatch, nullptr) ; | |
| 1492 if (!os) | |
| 1493 os = oppSeg->debugAddT(oppTs, SkOpSegment::kNoAliasMatch, nullptr); | |
| 1494 if (cs && os) cs->span()->debugAddOppAndMerge(id, log, os->span(), &csDe leted, &osDeleted); | |
| 1495 // cs = csWritable; | |
|
herb_g
2016/07/18 15:13:39
You have a bunch of commented out code in this rou
caryclark
2016/07/18 15:55:49
See reply above.
| |
| 1496 // os = osWritable; | |
| 1497 if ((ce && ce->deleted()) || (oe && oe->deleted())) { | |
| 1498 return; | |
| 1499 } | |
| 1500 } | |
| 1501 if (!ce || !oe) { | |
| 1502 if (!ce) | |
| 1503 ce = coinSeg->debugAddT(coinTe, SkOpSegment::kNoAliasMatch, nullptr) ; | |
| 1504 if (!oe) | |
| 1505 oe = oppSeg->debugAddT(oppTe, SkOpSegment::kNoAliasMatch, nullptr); | |
| 1506 if (ce && oe) ce->span()->debugAddOppAndMerge(id, log, oe->span(), &ceDe leted, &oeDeleted); | |
| 1507 // ce = ceWritable; | |
| 1508 // oe = oeWritable; | |
| 1509 } | |
| 1510 this->debugValidate(); | |
| 1511 if (csDeleted || osDeleted || ceDeleted || oeDeleted) { | |
| 1512 return; | |
| 1513 } | |
| 1514 if (!cs || !ce || cs->contains(ce) || !os || !oe || os->contains(oe)) { | |
| 1515 return; | |
| 1516 } | |
| 1517 // bool result = true; | |
| 1518 if (overlap) { | |
| 1519 if (overlap->coinPtTStart()->segment() == coinSeg) { | |
| 1520 log->record(kAddMissingExtend_Glitch, id, coinSeg, coinTs, coinT e, oppSeg, oppTs, oppTe); | |
| 1521 } else { | |
| 1522 if (oppTs > oppTe) { | |
| 1523 SkTSwap(coinTs, coinTe); | |
| 1524 SkTSwap(oppTs, oppTe); | |
| 1525 } | |
| 1526 log->record(kAddMissingExtend_Glitch, id, oppSeg, oppTs, oppTe, coin Seg, coinTs, coinTe); | |
| 1527 } | |
| 1528 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1529 // if (result) { | |
| 1530 // overlap->debugShow(); | |
| 1531 // } | |
| 1532 #endif | |
| 1533 } else { | |
| 1534 log->record(kAddMissingCoin_Glitch, id, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe); | |
| 1535 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1536 // fHead->debugShow(); | |
| 1537 #endif | |
| 1538 } | |
| 1539 this->debugValidate(); | |
| 1540 return; | |
| 1541 } | |
| 1542 | |
| 1543 // Extra commented-out lines keep this in sync with addMissing() | |
| 1544 /* detects overlaps of different coincident runs on same segment */ | |
| 1545 /* does not detect overlaps for pairs without any segments in common */ | |
| 1546 // returns true if caller should loop again | |
| 1263 void SkOpCoincidence::debugAddMissing(const char* id, SkPathOpsDebug::GlitchLog* log) const { | 1547 void SkOpCoincidence::debugAddMissing(const char* id, SkPathOpsDebug::GlitchLog* log) const { |
| 1264 const SkCoincidentSpans* outer = fHead; | 1548 const SkCoincidentSpans* outer = fHead; |
| 1265 if (!outer) { | 1549 if (!outer) { |
| 1266 return; | 1550 return; |
| 1267 } | 1551 } |
| 1552 // bool added = false; | |
| 1553 // fTop = outer; | |
| 1554 // fHead = nullptr; | |
| 1268 do { | 1555 do { |
| 1269 // addifmissing can modify the list that this is walking | 1556 // addifmissing can modify the list that this is walking |
| 1270 // save head so that walker can iterate over old data unperturbed | 1557 // save head so that walker can iterate over old data unperturbed |
| 1271 // addifmissing adds to head freely then add saved head in the end | 1558 // addifmissing adds to head freely then add saved head in the end |
| 1272 const SkOpSegment* outerCoin = outer->fCoinPtTStart->segment(); | 1559 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment(); |
| 1273 SkASSERT(outerCoin == outer->fCoinPtTEnd->segment()); | 1560 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment(); |
| 1274 const SkOpSegment* outerOpp = outer->fOppPtTStart->segment(); | 1561 if (outerCoin->done() || outerOpp->done()) { |
| 1275 SkASSERT(outerOpp == outer->fOppPtTEnd->segment()); | 1562 continue; |
| 1563 } | |
| 1276 const SkCoincidentSpans* inner = outer; | 1564 const SkCoincidentSpans* inner = outer; |
| 1277 while ((inner = inner->fNext)) { | 1565 while ((inner = inner->next())) { |
| 1566 this->debugValidate(); | |
| 1278 double overS, overE; | 1567 double overS, overE; |
| 1279 const SkOpSegment* innerCoin = inner->fCoinPtTStart->segment(); | 1568 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment(); |
| 1280 SkASSERT(innerCoin == inner->fCoinPtTEnd->segment()); | 1569 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment(); |
| 1281 const SkOpSegment* innerOpp = inner->fOppPtTStart->segment(); | 1570 if (innerCoin->done() || innerOpp->done()) { |
| 1282 SkASSERT(innerOpp == inner->fOppPtTEnd->segment()); | 1571 continue; |
| 1283 if (outerCoin == innerCoin | 1572 } |
| 1284 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, | 1573 if (outerCoin == innerCoin) { |
| 1285 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { | 1574 if (outerOpp != innerOpp |
| 1286 if (this->debugAddIfMissing(outer->fCoinPtTStart, outer->fCoinPt TEnd, | 1575 && this->overlap(outer->coinPtTStart(), outer->coinPtTEn d(), |
| 1287 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, | 1576 inner->coinPtTStart(), inner->coinPtTEnd(), &overS, &ove rE)) { |
| 1288 outer->fOppPtTStart, outer->fOppPtTEnd, | 1577 this->debugAddIfMissing(outer->coinPtTStart(), outer->coinPt TEnd(), |
| 1289 inner->fOppPtTStart, inner->fOppPtTEnd)) { | 1578 inner->coinPtTStart(), inner->coinPtTEnd(), overS, o verE, |
| 1290 log->record(kAddMissingCoin_Glitch, id, outer, inner->fCoinP tTStart); | 1579 outer->oppPtTStart(), outer->oppPtTEnd(), |
| 1291 } | 1580 inner->oppPtTStart(), inner->oppPtTEnd(), id, log); |
| 1292 } else if (outerCoin == innerOpp | 1581 } |
| 1293 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, | 1582 } else if (outerCoin == innerOpp) { |
| 1294 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { | 1583 if (outerOpp != innerCoin |
| 1295 if (this->debugAddIfMissing(outer->fCoinPtTStart, outer->fCoinPt TEnd, | 1584 && this->overlap(outer->coinPtTStart(), outer->coinPtTEn d(), |
| 1296 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, | 1585 inner->oppPtTStart(), inner->oppPtTEnd(), &overS, &overE )) { |
| 1297 outer->fOppPtTStart, outer->fOppPtTEnd, | 1586 this->debugAddIfMissing(outer->coinPtTStart(), outer->coinPt TEnd(), |
| 1298 inner->fCoinPtTStart, inner->fCoinPtTEnd)) { | 1587 inner->oppPtTStart(), inner->oppPtTEnd(), overS, ove rE, |
| 1299 log->record(kAddMissingCoin_Glitch, id, outer, inner->fOppPt TStart); | 1588 outer->oppPtTStart(), outer->oppPtTEnd(), |
| 1300 } | 1589 inner->coinPtTStart(), inner->coinPtTEnd(), id, log) ; |
| 1301 } else if (outerOpp == innerCoin | 1590 } |
| 1302 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, | 1591 } else if (outerOpp == innerCoin) { |
| 1303 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { | 1592 SkASSERT(outerCoin != innerOpp); |
| 1304 if (this->debugAddIfMissing(outer->fOppPtTStart, outer->fOppPtTE nd, | 1593 if (this->overlap(outer->oppPtTStart(), outer->oppPtTEnd(), |
| 1305 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, | 1594 inner->coinPtTStart(), inner->coinPtTEnd(), &overS, &ove rE)) { |
| 1306 outer->fCoinPtTStart, outer->fCoinPtTEnd, | 1595 this->debugAddIfMissing(outer->oppPtTStart(), outer->oppPtTE nd(), |
| 1307 inner->fOppPtTStart, inner->fOppPtTEnd)) { | 1596 inner->coinPtTStart(), inner->coinPtTEnd(), overS, o verE, |
| 1308 log->record(kAddMissingCoin_Glitch, id, outer, inner->fCoinP tTStart); | 1597 outer->coinPtTStart(), outer->coinPtTEnd(), |
| 1309 } | 1598 inner->oppPtTStart(), inner->oppPtTEnd(), id, log); |
| 1310 } else if (outerOpp == innerOpp | 1599 } |
| 1311 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, | 1600 } else if (outerOpp == innerOpp) { |
| 1312 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { | 1601 SkASSERT(outerCoin != innerCoin); |
| 1313 if (this->debugAddIfMissing(outer->fOppPtTStart, outer->fOppPtTE nd, | 1602 if (this->overlap(outer->oppPtTStart(), outer->oppPtTEnd(), |
| 1314 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, | 1603 inner->oppPtTStart(), inner->oppPtTEnd(), &overS, &overE )) { |
| 1315 outer->fCoinPtTStart, outer->fCoinPtTEnd, | 1604 this->debugAddIfMissing(outer->oppPtTStart(), outer->oppPtTE nd(), |
| 1316 inner->fCoinPtTStart, inner->fCoinPtTEnd)) { | 1605 inner->oppPtTStart(), inner->oppPtTEnd(), overS, ove rE, |
| 1317 log->record(kAddMissingCoin_Glitch, id, outer, inner->fOppPt TStart); | 1606 outer->coinPtTStart(), outer->coinPtTEnd(), |
| 1318 } | 1607 inner->coinPtTStart(), inner->coinPtTEnd(), id, log) ; |
| 1319 } else if (outerCoin != innerCoin) { | 1608 } |
| 1320 // check to see if outer span overlaps the inner span | 1609 } |
| 1321 // look for inner segment in pt-t list | 1610 this->debugValidate(); |
| 1322 // if present, and if t values are in coincident range | 1611 } |
| 1323 // add two pairs of new coincidence | 1612 } while ((outer = outer->next())); |
| 1324 const SkOpPtT* testS = outer->fCoinPtTStart->debugContains(inner Coin); | 1613 // this->restoreHead(); |
| 1325 const SkOpPtT* testE = outer->fCoinPtTEnd->debugContains(innerCo in); | 1614 return; |
| 1326 if (testS && testS->fT >= inner->fCoinPtTStart->fT | 1615 } |
| 1327 && testE && testE->fT <= inner->fCoinPtTEnd->fT | 1616 |
| 1328 && this->testForCoincidence(outer, testS, testE)) { | 1617 // Commented-out lines keep this in sync with release() |
| 1329 if (this->debugAddIfMissing(outer, testS, testE)) { | 1618 void SkOpCoincidence::debugRelease(const char* id, SkPathOpsDebug::GlitchLog* lo g, const SkOpSegment* deleted) const { |
| 1330 log->record(kAddMissingCoin_Glitch, id, outer, testS, te stE); | 1619 const SkCoincidentSpans* coin = fHead; |
| 1331 } | 1620 if (!coin) { |
| 1332 } else { | 1621 return; |
| 1333 testS = inner->fCoinPtTStart->debugContains(outerCoin); | 1622 } |
| 1334 testE = inner->fCoinPtTEnd->debugContains(outerCoin); | 1623 do { |
| 1335 if (testS && testS->fT >= outer->fCoinPtTStart->fT | 1624 if (coin->coinPtTStart()->segment() == deleted |
| 1336 && testE && testE->fT <= outer->fCoinPtTEnd->fT | 1625 || coin->coinPtTEnd()->segment() == deleted |
| 1337 && this->testForCoincidence(inner, testS, testE)) { | 1626 || coin->oppPtTStart()->segment() == deleted |
| 1338 if (this->debugAddIfMissing(inner, testS, testE)) { | 1627 || coin->oppPtTEnd()->segment() == deleted) { |
| 1339 log->record(kAddMissingCoin_Glitch, id, inner, testS , testE); | 1628 log->record(kReleasedSpan_Glitch, id, coin); |
| 1340 } | 1629 } |
| 1341 } | 1630 } while ((coin = coin->next())); |
| 1342 } | 1631 } |
| 1343 } | 1632 |
| 1344 } | 1633 // Commented-out lines keep this in sync with reorder() |
| 1345 } while ((outer = outer->fNext)); | 1634 // iterate through all coincident pairs, looking for ranges greater than 1 |
| 1346 } | 1635 // if found, see if the opposite pair can match it -- which may require |
| 1347 | 1636 // reordering the ptT pairs |
| 1637 void SkOpCoincidence::debugReorder(const char* id, SkPathOpsDebug::GlitchLog* lo g) const { | |
| 1638 const SkCoincidentSpans* coin = fHead; | |
| 1639 if (!coin) { | |
| 1640 return; | |
| 1641 } | |
| 1642 do { | |
| 1643 // most commonly, concidence are one span long; check for that first | |
| 1644 int intervals = coin->spanCount(); | |
| 1645 if (intervals = 1) { | |
| 1646 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1647 // SkASSERT(!coin->debugExpand(nullptr, nullptr)); | |
| 1648 #endif | |
| 1649 continue; | |
| 1650 } | |
| 1651 coin->debugExpand(id, log); | |
| 1652 if (coin->spanCount() <= 0) { | |
| 1653 return; | |
| 1654 } | |
| 1655 // check to see if every span in coin has a mate in opp | |
| 1656 const SkOpSpan* start = coin->coinPtTStart()->span()->upCast(); | |
| 1657 bool flipped = coin->flipped(); | |
| 1658 const SkOpSpanBase* oppStartBase = coin->oppPtTStart()->span(); | |
| 1659 const SkOpSpan* oppStart = flipped ? oppStartBase->prev() : oppStartBase ->upCast(); | |
| 1660 SkDebugf("", start, oppStart); | |
| 1661 } while ((coin = coin->next())); | |
| 1662 return; | |
| 1663 } | |
| 1664 | |
| 1665 // Commented-out lines keep this in sync with expand() | |
| 1666 // expand the range by checking adjacent spans for coincidence | |
| 1348 bool SkOpCoincidence::debugExpand(const char* id, SkPathOpsDebug::GlitchLog* log ) const { | 1667 bool SkOpCoincidence::debugExpand(const char* id, SkPathOpsDebug::GlitchLog* log ) const { |
| 1349 const SkCoincidentSpans* coin = fHead; | 1668 const SkCoincidentSpans* coin = fHead; |
| 1350 if (!coin) { | 1669 if (!coin) { |
| 1351 return false; | 1670 return false; |
| 1352 } | 1671 } |
| 1353 bool expanded = false; | 1672 bool expanded = false; |
| 1354 do { | 1673 do { |
| 1355 const SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); | 1674 if (coin->debugExpand(id, log)) { |
| 1356 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); | 1675 // check to see if multiple spans expanded so they are now identical |
| 1357 const SkOpSegment* segment = coin->fCoinPtTStart->segment(); | 1676 const SkCoincidentSpans* test = fHead; |
| 1358 const SkOpSegment* oppSegment = coin->fOppPtTStart->segment(); | 1677 do { |
| 1359 const SkOpSpan* prev = start->prev(); | 1678 if (coin == test) { |
| 1360 if (prev && prev->debugContains(oppSegment)) { | 1679 continue; |
| 1361 double midT = (prev->t() + start->t()) / 2; | 1680 } |
| 1362 if (segment->isClose(midT, oppSegment)) { | 1681 if (coin->coinPtTStart() == test->coinPtTStart() |
| 1363 log->record(kExpandCoin_Glitch, id, coin, prev); | 1682 && coin->oppPtTStart() == test->oppPtTStart()) { |
| 1364 } | 1683 if (log) log->record(kExpandCoin_Glitch, id, fHead, test->co inPtTStart()); |
| 1365 } | 1684 break; |
| 1366 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); | 1685 } |
| 1367 if (next && next->debugContains(oppSegment)) { | 1686 } while ((test = test->next())); |
| 1368 double midT = (end->t() + next->t()) / 2; | 1687 expanded = true; |
| 1369 if (segment->isClose(midT, oppSegment)) { | 1688 } |
| 1370 log->record(kExpandCoin_Glitch, id, coin, next); | 1689 } while ((coin = coin->next())); |
| 1371 } | |
| 1372 } | |
| 1373 } while ((coin = coin->fNext)); | |
| 1374 return expanded; | 1690 return expanded; |
| 1375 } | 1691 } |
| 1376 | 1692 |
| 1377 void SkOpCoincidence::debugFixAligned(const char* id, SkPathOpsDebug::GlitchLog* log) const { | 1693 // Commented-out lines keep this in sync with removeCollapsed() |
| 1694 void SkOpCoincidence::debugRemoveCollapsed(const char* id, SkPathOpsDebug::Glitc hLog* log) const { | |
| 1378 const SkCoincidentSpans* coin = fHead; | 1695 const SkCoincidentSpans* coin = fHead; |
| 1379 if (!coin) { | 1696 if (!coin) { |
| 1380 return; | 1697 return; |
| 1381 } | 1698 } |
| 1382 do { | 1699 // SkCoincidentSpans** priorPtr = &fHead; |
| 1383 if (coin->fCoinPtTStart->deleted()) { | 1700 do { |
| 1384 log->record(kDeletedCoin_Glitch, id, coin, coin->fCoinPtTStart); | 1701 if (coin->coinPtTStart() == coin->coinPtTEnd()) { |
| 1385 } | 1702 return; |
| 1386 if (coin->fCoinPtTEnd->deleted()) { | 1703 } |
| 1387 log->record(kDeletedCoin_Glitch, id, coin, coin->fCoinPtTEnd); | 1704 if (coin->oppPtTStart() == coin->oppPtTEnd()) { |
| 1388 } | 1705 return; |
| 1389 if (coin->fOppPtTStart->deleted()) { | 1706 } |
| 1390 log->record(kDeletedCoin_Glitch, id, coin, coin->fOppPtTStart); | 1707 if (coin->coinPtTStart()->collapsed(coin->coinPtTEnd())) { |
| 1391 } | 1708 log->record(kCollapsedCoin_Glitch, id, coin); |
| 1392 if (coin->fOppPtTEnd->deleted()) { | 1709 // continue; |
| 1393 log->record(kDeletedCoin_Glitch, id, coin, coin->fOppPtTEnd); | 1710 } |
| 1394 } | 1711 if (coin->oppPtTStart()->collapsed(coin->oppPtTEnd())) { |
| 1395 } while ((coin = coin->fNext)); | 1712 log->record(kCollapsedCoin_Glitch, id, coin, coin); |
| 1396 coin = fHead; | 1713 // continue; |
| 1397 do { | 1714 } |
| 1398 if (coin->fCoinPtTStart->collapsed(coin->fCoinPtTEnd)) { | 1715 // priorPtr = &coin->nextPtr(); |
| 1399 log->record(kCollapsedCoin_Glitch, id, coin, coin->fCoinPtTStart); | 1716 } while ((coin = coin->next())); |
| 1400 } | 1717 return; |
| 1401 if (coin->fOppPtTStart->collapsed(coin->fOppPtTEnd)) { | 1718 } |
| 1402 log->record(kCollapsedCoin_Glitch, id, coin, coin->fOppPtTStart); | 1719 |
| 1403 } | 1720 // Commented-out lines keep this in sync with mark() |
| 1404 } while ((coin = coin->fNext)); | 1721 /* this sets up the coincidence links in the segments when the coincidence cross es multiple spans */ |
| 1405 } | |
| 1406 | |
| 1407 void SkOpCoincidence::debugMark(const char* id, SkPathOpsDebug::GlitchLog* log) const { | 1722 void SkOpCoincidence::debugMark(const char* id, SkPathOpsDebug::GlitchLog* log) const { |
| 1408 const SkCoincidentSpans* coin = fHead; | 1723 const SkCoincidentSpans* coin = fHead; |
| 1409 if (!coin) { | 1724 if (!coin) { |
| 1410 return; | 1725 return; |
| 1411 } | 1726 } |
| 1412 do { | 1727 do { |
| 1413 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); | 1728 const SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast(); |
| 1414 const SkOpSpanBase* oldEnd = end; | 1729 // SkASSERT(start->deleted()); |
| 1415 const SkOpSpan* start = coin->fCoinPtTStart->span()->debugStarter(&end); | 1730 const SkOpSpanBase* end = coin->coinPtTEndWritable()->span(); |
| 1416 const SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); | 1731 // SkASSERT(end->deleted()); |
| 1417 const SkOpSpanBase* oOldEnd = oEnd; | 1732 const SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span(); |
| 1418 const SkOpSpanBase* oStart = coin->fOppPtTStart->span()->debugStarter(&o End); | 1733 // SkASSERT(oStart->deleted()); |
| 1419 bool flipped = (end == oldEnd) != (oEnd == oOldEnd); | 1734 const SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span(); |
| 1735 // SkASSERT(oEnd->deleted()); | |
| 1736 bool flipped = coin->flipped(); | |
| 1420 if (flipped) { | 1737 if (flipped) { |
| 1421 SkTSwap(oStart, oEnd); | 1738 SkTSwap(oStart, oEnd); |
| 1422 } | 1739 } |
| 1740 /* coin and opp spans may not match up. Mark the ends, and then let the interior | |
| 1741 get marked as many times as the spans allow */ | |
| 1742 start->debugInsertCoincidence(id, log, oStart->upCast()); | |
| 1743 end->debugInsertCoinEnd(id, log, oEnd); | |
| 1744 const SkOpSegment* segment = start->segment(); | |
| 1745 const SkOpSegment* oSegment = oStart->segment(); | |
| 1423 const SkOpSpanBase* next = start; | 1746 const SkOpSpanBase* next = start; |
| 1424 const SkOpSpanBase* oNext = oStart; | 1747 const SkOpSpanBase* oNext = oStart; |
| 1748 while ((next = next->upCast()->next()) != end) { | |
| 1749 if (next->upCast()->debugInsertCoincidence(id, log, oSegment, flippe d), false) { | |
| 1750 return; | |
| 1751 } | |
| 1752 } | |
| 1753 while ((oNext = oNext->upCast()->next()) != oEnd) { | |
| 1754 if (oNext->upCast()->debugInsertCoincidence(id, log, segment, flippe d), false) { | |
| 1755 return; | |
| 1756 } | |
| 1757 } | |
| 1758 } while ((coin = coin->next())); | |
| 1759 return; | |
| 1760 } | |
| 1761 #endif | |
| 1762 | |
| 1763 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1764 // Commented-out lines keep this in sync with markCollapsed() | |
| 1765 void SkOpCoincidence::debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchL og* log, const SkCoincidentSpans* coin, const SkOpPtT* test) const { | |
| 1766 while (coin) { | |
| 1767 if (coin->collapsed(test)) { | |
| 1768 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinP tTEnd()->fT)) { | |
| 1769 log->record(kCollapsedCoin_Glitch, id, coin); | |
| 1770 } | |
| 1771 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtT End()->fT)) { | |
| 1772 log->record(kCollapsedCoin_Glitch, id, coin); | |
| 1773 } | |
| 1774 } | |
| 1775 coin = coin->next(); | |
| 1776 } | |
| 1777 } | |
| 1778 | |
| 1779 // Commented-out lines keep this in sync with markCollapsed() | |
| 1780 void SkOpCoincidence::debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchL og* log, const SkOpPtT* test) const { | |
| 1781 this->debugMarkCollapsed(id, log, fHead, test); | |
| 1782 this->debugMarkCollapsed(id, log, fTop, test); | |
| 1783 } | |
| 1784 #endif | |
| 1785 | |
| 1786 void SkCoincidentSpans::debugShow() const { | |
| 1787 SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__, | |
| 1788 coinPtTStart()->segment()->debugID(), | |
| 1789 coinPtTStart()->fT, coinPtTEnd()->fT); | |
| 1790 SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__, | |
| 1791 oppPtTStart()->segment()->debugID(), | |
| 1792 oppPtTStart()->fT, oppPtTEnd()->fT); | |
| 1793 } | |
| 1794 | |
| 1795 void SkOpCoincidence::debugShowCoincidence() const { | |
| 1796 #if DEBUG_COINCIDENCE | |
| 1797 const SkCoincidentSpans* span = fHead; | |
| 1798 while (span) { | |
| 1799 span->debugShow(); | |
| 1800 span = span->next(); | |
| 1801 } | |
| 1802 #endif | |
| 1803 } | |
| 1804 | |
| 1805 #if DEBUG_COINCIDENCE | |
| 1806 static void DebugValidate(const SkOpSpanBase* next, const SkOpSpanBase* end, | |
| 1807 double oStart, double oEnd, const SkOpSegment* oSegment, | |
| 1808 const char* id, SkPathOpsDebug::GlitchLog* log) { | |
| 1809 SkASSERT(next != end); | |
| 1810 SkASSERT(!next->contains(end) || log); | |
| 1811 if (next->t() > end->t()) { | |
| 1812 SkTSwap(next, end); | |
| 1813 } | |
| 1814 do { | |
| 1815 const SkOpPtT* ptT = next->ptT(); | |
| 1816 int index = 0; | |
| 1817 bool somethingBetween; | |
| 1425 do { | 1818 do { |
| 1426 next = next->upCast()->next(); | 1819 ++index; |
| 1427 oNext = flipped ? oNext->prev() : oNext->upCast()->next(); | 1820 ptT = ptT->next(); |
| 1428 if (next == end || oNext == oEnd) { | 1821 const SkOpPtT* checkPtT = next->ptT(); |
| 1822 if (ptT == checkPtT) { | |
| 1429 break; | 1823 break; |
| 1430 } | 1824 } |
| 1431 if (!next->containsCoinEnd(oNext)) { | 1825 bool looped = false; |
| 1432 log->record(kMarkCoinEnd_Glitch, id, next, oNext); | 1826 for (int check = 0; check < index; ++check) { |
| 1433 } | 1827 if ((looped = checkPtT == ptT)) { |
| 1434 const SkOpSpan* nextSpan = next->upCast(); | 1828 break; |
| 1435 const SkOpSpan* oNextSpan = oNext->upCast(); | 1829 } |
| 1436 if (!nextSpan->containsCoincidence(oNextSpan)) { | 1830 checkPtT = checkPtT->next(); |
| 1437 log->record(kMarkCoinInsert_Glitch, id, nextSpan, oNextSpan); | 1831 } |
| 1438 } | 1832 if (looped) { |
| 1833 SkASSERT(0); | |
| 1834 break; | |
| 1835 } | |
| 1836 if (ptT->deleted()) { | |
| 1837 continue; | |
| 1838 } | |
| 1839 if (ptT->segment() != oSegment) { | |
| 1840 continue; | |
| 1841 } | |
| 1842 somethingBetween |= between(oStart, ptT->fT, oEnd); | |
| 1439 } while (true); | 1843 } while (true); |
| 1440 } while ((coin = coin->fNext)); | 1844 SkASSERT(somethingBetween); |
| 1441 } | 1845 } while (next != end && (next = next->upCast()->next())); |
| 1442 #endif | 1846 } |
| 1443 | 1847 |
| 1444 void SkOpCoincidence::debugShowCoincidence() const { | 1848 static void DebugCheckOverlap(const SkCoincidentSpans* test, const SkCoincidentS pans* list, |
| 1445 SkCoincidentSpans* span = fHead; | 1849 const char* id, SkPathOpsDebug::GlitchLog* log) { |
| 1446 while (span) { | 1850 if (!list) { |
| 1447 SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__, | 1851 return; |
| 1448 span->fCoinPtTStart->segment()->debugID(), | 1852 } |
| 1449 span->fCoinPtTStart->fT, span->fCoinPtTEnd->fT); | 1853 const SkOpSegment* coinSeg = test->coinPtTStart()->segment(); |
| 1450 SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__, | 1854 SkASSERT(coinSeg == test->coinPtTEnd()->segment()); |
| 1451 span->fOppPtTStart->segment()->debugID(), | 1855 const SkOpSegment* oppSeg = test->oppPtTStart()->segment(); |
| 1452 span->fOppPtTStart->fT, span->fOppPtTEnd->fT); | 1856 SkASSERT(oppSeg == test->oppPtTEnd()->segment()); |
| 1453 span = span->fNext; | 1857 SkASSERT(coinSeg != test->oppPtTStart()->segment()); |
| 1454 } | 1858 SkDEBUGCODE(double tcs = test->coinPtTStart()->fT); |
| 1455 } | 1859 SkASSERT(between(0, tcs, 1)); |
| 1456 | 1860 SkDEBUGCODE(double tce = test->coinPtTEnd()->fT); |
| 1861 SkASSERT(between(0, tce, 1)); | |
| 1862 SkASSERT(tcs < tce); | |
| 1863 double tos = test->oppPtTStart()->fT; | |
| 1864 SkASSERT(between(0, tos, 1)); | |
| 1865 double toe = test->oppPtTEnd()->fT; | |
| 1866 SkASSERT(between(0, toe, 1)); | |
| 1867 SkASSERT(tos != toe); | |
| 1868 if (tos > toe) { | |
| 1869 SkTSwap(tos, toe); | |
| 1870 } | |
| 1871 do { | |
| 1872 double lcs, lce, los, loe; | |
| 1873 if (coinSeg == list->coinPtTStart()->segment()) { | |
| 1874 if (oppSeg != list->oppPtTStart()->segment()) { | |
| 1875 continue; | |
| 1876 } | |
| 1877 lcs = list->coinPtTStart()->fT; | |
| 1878 lce = list->coinPtTEnd()->fT; | |
| 1879 los = list->oppPtTStart()->fT; | |
| 1880 loe = list->oppPtTEnd()->fT; | |
| 1881 if (los > loe) { | |
| 1882 SkTSwap(los, loe); | |
| 1883 } | |
| 1884 } else if (coinSeg == list->oppPtTStart()->segment()) { | |
| 1885 if (oppSeg != list->coinPtTStart()->segment()) { | |
| 1886 continue; | |
| 1887 } | |
| 1888 lcs = list->oppPtTStart()->fT; | |
| 1889 lce = list->oppPtTEnd()->fT; | |
| 1890 if (lcs > lce) { | |
| 1891 SkTSwap(lcs, lce); | |
| 1892 } | |
| 1893 los = list->coinPtTStart()->fT; | |
| 1894 loe = list->coinPtTEnd()->fT; | |
| 1895 } else { | |
| 1896 continue; | |
| 1897 } | |
| 1898 SkASSERT(tce < lcs || lce < tcs); | |
| 1899 SkASSERT(toe < los || loe < tos); | |
| 1900 } while ((list = list->next())); | |
| 1901 } | |
| 1902 | |
| 1903 | |
| 1904 static void DebugCheckOverlapTop(const SkCoincidentSpans* head, const SkCoincide ntSpans* opt, | |
| 1905 const char* id, SkPathOpsDebug::GlitchLog* log) { | |
| 1906 // check for overlapping coincident spans | |
| 1907 const SkCoincidentSpans* test = head; | |
| 1908 while (test) { | |
| 1909 const SkCoincidentSpans* next = test->next(); | |
| 1910 DebugCheckOverlap(test, next, id, log); | |
| 1911 DebugCheckOverlap(test, opt, id, log); | |
| 1912 test = next; | |
| 1913 } | |
| 1914 } | |
| 1915 | |
| 1916 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1917 void SkOpCoincidence::debugCheckOverlap(const char* id, SkPathOpsDebug::GlitchLo g* log) const { | |
| 1918 DebugCheckOverlapTop(fHead, fTop, id, log); | |
| 1919 DebugCheckOverlapTop(fTop, nullptr, id, log); | |
| 1920 } | |
| 1921 #endif | |
| 1922 | |
| 1923 static void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans * opt, | |
| 1924 const char* id, SkPathOpsDebug::GlitchLog* log) { | |
| 1925 // look for pts inside coincident spans that are not inside the opposite spa ns | |
| 1926 const SkCoincidentSpans* coin = head; | |
| 1927 while (coin) { | |
| 1928 SkASSERT(SkOpCoincidence::Ordered(coin->coinPtTStart()->segment(), | |
| 1929 coin->oppPtTStart()->segment())); | |
| 1930 SkASSERT(coin->coinPtTStart()->span()->ptT() == coin->coinPtTStart()); | |
| 1931 SkASSERT(coin->coinPtTEnd()->span()->ptT() == coin->coinPtTEnd()); | |
| 1932 SkASSERT(coin->oppPtTStart()->span()->ptT() == coin->oppPtTStart()); | |
| 1933 SkASSERT(coin->oppPtTEnd()->span()->ptT() == coin->oppPtTEnd()); | |
| 1934 DebugValidate(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(), | |
| 1935 coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStar t()->segment(), | |
| 1936 id, log); | |
| 1937 DebugValidate(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(), | |
| 1938 coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTS tart()->segment(), | |
| 1939 id, log); | |
| 1940 coin = coin->next(); | |
| 1941 } | |
| 1942 DebugCheckOverlapTop(head, opt, id, log); | |
| 1943 } | |
| 1944 #endif | |
| 1945 | |
| 1946 void SkOpCoincidence::debugValidate() const { | |
| 1457 #if DEBUG_COINCIDENCE | 1947 #if DEBUG_COINCIDENCE |
| 1948 // if (fGlobalState->debugCheckHealth()) { | |
| 1949 // return; | |
| 1950 // } | |
| 1951 DebugValidate(fHead, fTop, nullptr, nullptr); | |
| 1952 DebugValidate(fTop, nullptr, nullptr, nullptr); | |
| 1953 #endif | |
| 1954 } | |
| 1955 | |
| 1956 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1957 void SkOpCoincidence::debugCheckValid(const char* id, SkPathOpsDebug::GlitchLog* log) const { | |
| 1958 DebugValidate(fHead, fTop, id, log); | |
| 1959 DebugValidate(fTop, nullptr, id, log); | |
| 1960 } | |
| 1961 #endif | |
| 1962 | |
| 1963 #if DEBUG_COINCIDENCE_VERBOSE | |
| 1458 void SkOpContour::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* lo g) const { | 1964 void SkOpContour::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* lo g) const { |
| 1459 const SkOpSegment* segment = &fHead; | 1965 const SkOpSegment* segment = &fHead; |
| 1460 do { | 1966 do { |
| 1461 segment->debugCheckHealth(id, log); | 1967 segment->debugCheckHealth(id, log); |
| 1462 } while ((segment = segment->next())); | 1968 } while ((segment = segment->next())); |
| 1463 } | 1969 } |
| 1464 | 1970 |
| 1465 void SkOpContour::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log, | 1971 // commmented-out lines keep this aligned with missingCoincidence() |
| 1466 const SkOpCoincidence* coincidence) const { | 1972 void SkOpContour::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log) const { |
| 1973 // SkASSERT(fCount > 0); | |
| 1467 const SkOpSegment* segment = &fHead; | 1974 const SkOpSegment* segment = &fHead; |
| 1975 // bool result = false; | |
| 1468 do { | 1976 do { |
| 1469 segment->debugMissingCoincidence(id, log, coincidence); | 1977 if (fState->angleCoincidence()) { |
| 1470 } while ((segment = segment->next())); | 1978 // #if DEBUG_ANGLE |
| 1979 // segment->debugCheckAngleCoin(); | |
| 1980 // #endif | |
| 1981 } else if (segment->debugMissingCoincidence(id, log), false) { | |
| 1982 // result = true; | |
| 1983 // see FIXME in missingCoincidence() | |
| 1984 // | |
| 1985 // | |
| 1986 // | |
| 1987 // continue; | |
| 1988 } | |
| 1989 segment = segment->next(); | |
| 1990 } while (segment); | |
| 1991 return; | |
| 1471 } | 1992 } |
| 1472 #endif | 1993 #endif |
| 1473 | 1994 |
| 1474 void SkOpSegment::debugValidate() const { | 1995 void SkOpSegment::debugValidate() const { |
| 1996 #if DEBUG_COINCIDENCE | |
| 1997 if (this->globalState()->debugCheckHealth()) { | |
| 1998 return; | |
| 1999 } | |
| 2000 #endif | |
| 1475 #if DEBUG_VALIDATE | 2001 #if DEBUG_VALIDATE |
| 1476 const SkOpSpanBase* span = &fHead; | 2002 const SkOpSpanBase* span = &fHead; |
| 1477 double lastT = -1; | 2003 double lastT = -1; |
| 1478 const SkOpSpanBase* prev = nullptr; | 2004 const SkOpSpanBase* prev = nullptr; |
| 1479 int count = 0; | 2005 int count = 0; |
| 1480 int done = 0; | 2006 int done = 0; |
| 1481 do { | 2007 do { |
| 1482 if (!span->final()) { | 2008 if (!span->final()) { |
| 1483 ++count; | 2009 ++count; |
| 1484 done += span->upCast()->done() ? 1 : 0; | 2010 done += span->upCast()->done() ? 1 : 0; |
| 1485 } | 2011 } |
| 1486 SkASSERT(span->segment() == this); | 2012 SkASSERT(span->segment() == this); |
| 1487 SkASSERT(!prev || prev->upCast()->next() == span); | 2013 SkASSERT(!prev || prev->upCast()->next() == span); |
| 1488 SkASSERT(!prev || prev == span->prev()); | 2014 SkASSERT(!prev || prev == span->prev()); |
| 1489 prev = span; | 2015 prev = span; |
| 1490 double t = span->ptT()->fT; | 2016 double t = span->ptT()->fT; |
| 1491 SkASSERT(lastT < t); | 2017 SkASSERT(lastT < t); |
| 1492 lastT = t; | 2018 lastT = t; |
| 1493 span->debugValidate(); | 2019 span->debugValidate(); |
| 1494 } while (!span->final() && (span = span->upCast()->next())); | 2020 } while (!span->final() && (span = span->upCast()->next())); |
| 1495 SkASSERT(count == fCount); | 2021 SkASSERT(count == fCount); |
| 1496 SkASSERT(done == fDoneCount); | 2022 SkASSERT(done == fDoneCount); |
| 1497 SkASSERT(count >= fDoneCount); | 2023 SkASSERT(count >= fDoneCount); |
| 1498 SkASSERT(span->final()); | 2024 SkASSERT(span->final()); |
| 1499 span->debugValidate(); | 2025 span->debugValidate(); |
| 1500 #endif | 2026 #endif |
| 1501 } | 2027 } |
| 1502 | 2028 |
| 1503 bool SkOpSpanBase::debugAlignedEnd(double t, const SkPoint& pt) const { | 2029 #if DEBUG_COINCIDENCE_VERBOSE |
| 1504 SkASSERT(zero_or_one(t)); | 2030 // Commented-out lines keep this in sync with addOppAndMerge() |
| 1505 const SkOpSegment* segment = this->segment(); | 2031 // If the added points envelop adjacent spans, merge them in. |
| 1506 SkASSERT(t ? segment->lastPt() == pt : segment->pts()[0] == pt); | 2032 void SkOpSpanBase::debugAddOppAndMerge(const char* id, SkPathOpsDebug::GlitchLog * log, const SkOpSpanBase* opp, bool* spanDeleted, bool* oppDeleted) const { |
| 1507 if (!debugAlignedInner()) { | 2033 if (this->ptT()->debugAddOpp(opp->ptT())) { |
| 1508 return false; | 2034 this->debugCheckForCollapsedCoincidence(id, log); |
| 1509 } | 2035 } |
| 1510 if ((t ? segment->lastPt() : segment->pts()[0]) != pt) { | 2036 // compute bounds of points in span |
| 1511 return false; | 2037 SkPathOpsBounds bounds; |
| 2038 bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin); | |
| 2039 const SkOpPtT* head = this->ptT(); | |
| 2040 const SkOpPtT* nextPt = head; | |
| 2041 do { | |
| 2042 bounds.add(nextPt->fPt); | |
| 2043 } while ((nextPt = nextPt->next()) != head); | |
| 2044 if (!bounds.width() && !bounds.height()) { | |
| 2045 return; | |
| 1512 } | 2046 } |
| 1513 const SkOpPtT* ptT = &this->fPtT; | 2047 this->debugMergeContained(id, log, bounds, spanDeleted); |
| 1514 SkASSERT(t == ptT->fT); | 2048 opp->debugMergeContained(id, log, bounds, oppDeleted); |
| 1515 SkASSERT(pt == ptT->fPt); | 2049 } |
| 1516 const SkOpPtT* test = ptT, * stopPtT = ptT; | 2050 |
| 1517 while ((test = test->next()) != stopPtT) { | 2051 // Commented-out lines keep this in sync with checkForCollapsedCoincidence() |
| 1518 const SkOpSegment* other = test->segment(); | 2052 void SkOpSpanBase::debugCheckForCollapsedCoincidence(const char* id, SkPathOpsDe bug::GlitchLog* log) const { |
| 1519 if (other == this->segment()) { | 2053 const SkOpCoincidence* coins = this->globalState()->coincidence(); |
| 2054 if (coins->isEmpty()) { | |
| 2055 return; | |
| 2056 } | |
| 2057 // the insert above may have put both ends of a coincident run in the same span | |
| 2058 // for each coincident ptT in loop; see if its opposite in is also in the loop | |
| 2059 // this implementation is the motivation for marking that a ptT is referenced by a coincident span | |
| 2060 const SkOpPtT* head = this->ptT(); | |
| 2061 const SkOpPtT* test = head; | |
| 2062 do { | |
| 2063 if (!test->coincident()) { | |
| 1520 continue; | 2064 continue; |
| 1521 } | 2065 } |
| 1522 if (!zero_or_one(test->fT)) { | 2066 coins->debugMarkCollapsed(id, log, test); |
| 1523 continue; | 2067 } while ((test = test->next()) != head); |
| 1524 } | |
| 1525 if ((test->fT ? other->lastPt() : other->pts()[0]) != pt) { | |
| 1526 return false; | |
| 1527 } | |
| 1528 } | |
| 1529 return this->fAligned; | |
| 1530 } | 2068 } |
| 1531 | 2069 #endif |
| 1532 bool SkOpSpanBase::debugAlignedInner() const { | |
| 1533 // force the spans to share points and t values | |
| 1534 const SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT; | |
| 1535 const SkPoint& pt = ptT->fPt; | |
| 1536 do { | |
| 1537 if (ptT->fPt != pt) { | |
| 1538 return false; | |
| 1539 } | |
| 1540 const SkOpSpanBase* span = ptT->span(); | |
| 1541 const SkOpPtT* test = ptT; | |
| 1542 do { | |
| 1543 if ((test = test->next()) == stopPtT) { | |
| 1544 break; | |
| 1545 } | |
| 1546 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *tes t)) { | |
| 1547 return false; | |
| 1548 } | |
| 1549 } while (true); | |
| 1550 } while ((ptT = ptT->next()) != stopPtT); | |
| 1551 return true; | |
| 1552 } | |
| 1553 | 2070 |
| 1554 bool SkOpSpanBase::debugCoinEndLoopCheck() const { | 2071 bool SkOpSpanBase::debugCoinEndLoopCheck() const { |
| 1555 int loop = 0; | 2072 int loop = 0; |
| 1556 const SkOpSpanBase* next = this; | 2073 const SkOpSpanBase* next = this; |
| 1557 SkOpSpanBase* nextCoin; | 2074 SkOpSpanBase* nextCoin; |
| 1558 do { | 2075 do { |
| 1559 nextCoin = next->fCoinEnd; | 2076 nextCoin = next->fCoinEnd; |
| 1560 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); | 2077 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); |
| 1561 for (int check = 1; check < loop - 1; ++check) { | 2078 for (int check = 1; check < loop - 1; ++check) { |
| 1562 const SkOpSpanBase* checkCoin = this->fCoinEnd; | 2079 const SkOpSpanBase* checkCoin = this->fCoinEnd; |
| 1563 const SkOpSpanBase* innerCoin = checkCoin; | 2080 const SkOpSpanBase* innerCoin = checkCoin; |
| 1564 for (int inner = check + 1; inner < loop; ++inner) { | 2081 for (int inner = check + 1; inner < loop; ++inner) { |
| 1565 innerCoin = innerCoin->fCoinEnd; | 2082 innerCoin = innerCoin->fCoinEnd; |
| 1566 if (checkCoin == innerCoin) { | 2083 if (checkCoin == innerCoin) { |
| 1567 SkDebugf("*** bad coincident end loop ***\n"); | 2084 SkDebugf("*** bad coincident end loop ***\n"); |
| 1568 return false; | 2085 return false; |
| 1569 } | 2086 } |
| 1570 } | 2087 } |
| 1571 } | 2088 } |
| 1572 ++loop; | 2089 ++loop; |
| 1573 } while ((next = nextCoin) && next != this); | 2090 } while ((next = nextCoin) && next != this); |
| 1574 return true; | 2091 return true; |
| 1575 } | 2092 } |
| 1576 | 2093 |
| 1577 bool SkOpSpanBase::debugContains(const SkOpSegment* segment) const { | 2094 #if DEBUG_COINCIDENCE_VERBOSE |
| 1578 const SkOpPtT* start = &fPtT; | 2095 // Commented-out lines keep this in sync with insertCoinEnd() |
| 1579 const SkOpPtT* walk = start; | 2096 void SkOpSpanBase::debugInsertCoinEnd(const char* id, SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* coin) const { |
| 1580 while ((walk = walk->next()) != start) { | 2097 if (containsCoinEnd(coin)) { |
| 1581 if (walk->segment() == segment) { | 2098 // SkASSERT(coin->containsCoinEnd(this)); |
| 1582 return true; | 2099 return; |
| 2100 } | |
| 2101 debugValidate(); | |
| 2102 // SkASSERT(this != coin); | |
| 2103 log->record(kMarkCoinEnd_Glitch, id, this, coin); | |
| 2104 // coin->fCoinEnd = this->fCoinEnd; | |
| 2105 // this->fCoinEnd = coinNext; | |
| 2106 debugValidate(); | |
| 2107 } | |
| 2108 | |
| 2109 // Commented-out lines keep this in sync with mergeContained() | |
| 2110 void SkOpSpanBase::debugMergeContained(const char* id, SkPathOpsDebug::GlitchLog * log, const SkPathOpsBounds& bounds, bool* deleted) const { | |
| 2111 // while adjacent spans' points are contained by the bounds, merge them | |
| 2112 const SkOpSpanBase* prev = this; | |
| 2113 const SkOpSegment* seg = this->segment(); | |
| 2114 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisj oint(prev, this)) { | |
| 2115 if (prev->prev()) { | |
| 2116 log->record(kMergeContained_Glitch, id, this, prev); | |
| 2117 } else if (this->final()) { | |
| 2118 log->record(kMergeContained_Glitch, id, this, prev); | |
| 2119 // return; | |
| 2120 } else { | |
| 2121 log->record(kMergeContained_Glitch, id, prev, this); | |
| 1583 } | 2122 } |
| 1584 } | 2123 } |
| 1585 return false; | 2124 const SkOpSpanBase* current = this; |
| 2125 const SkOpSpanBase* next = this; | |
| 2126 while (next->upCastable() && (next = next->upCast()->next()) | |
| 2127 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) { | |
| 2128 if (!current->prev() && next->final()) { | |
| 2129 log->record(kMergeContained_Glitch, id, next, current); | |
| 2130 current = next; | |
| 2131 } | |
| 2132 if (current->prev()) { | |
| 2133 log->record(kMergeContained_Glitch, id, next, current); | |
| 2134 current = next; | |
| 2135 } else { | |
| 2136 log->record(kMergeContained_Glitch, id, next, current); | |
| 2137 current = next; | |
| 2138 } | |
| 2139 } | |
| 2140 #if DEBUG_COINCIDENCE | |
| 2141 // this->globalState()->coincidence()->debugValidate(); | |
| 2142 #endif | |
| 1586 } | 2143 } |
| 2144 #endif | |
| 1587 | 2145 |
| 1588 const SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const { | 2146 const SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const { |
| 1589 const SkOpSpanBase* end = *endPtr; | 2147 const SkOpSpanBase* end = *endPtr; |
| 1590 SkASSERT(this->segment() == end->segment()); | 2148 SkASSERT(this->segment() == end->segment()); |
| 1591 const SkOpSpanBase* result; | 2149 const SkOpSpanBase* result; |
| 1592 if (t() < end->t()) { | 2150 if (t() < end->t()) { |
| 1593 result = this; | 2151 result = this; |
| 1594 } else { | 2152 } else { |
| 1595 result = end; | 2153 result = end; |
| 1596 *endPtr = this; | 2154 *endPtr = this; |
| 1597 } | 2155 } |
| 1598 return result->upCast(); | 2156 return result->upCast(); |
| 1599 } | 2157 } |
| 1600 | 2158 |
| 1601 void SkOpSpanBase::debugValidate() const { | 2159 void SkOpSpanBase::debugValidate() const { |
| 2160 #if DEBUG_COINCIDENCE | |
| 2161 if (this->globalState()->debugCheckHealth()) { | |
| 2162 return; | |
| 2163 } | |
| 2164 #endif | |
| 1602 #if DEBUG_VALIDATE | 2165 #if DEBUG_VALIDATE |
| 1603 const SkOpPtT* ptT = &fPtT; | 2166 const SkOpPtT* ptT = &fPtT; |
| 1604 SkASSERT(ptT->span() == this); | 2167 SkASSERT(ptT->span() == this); |
| 1605 do { | 2168 do { |
| 1606 // SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); | 2169 // SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); |
| 1607 ptT->debugValidate(); | 2170 ptT->debugValidate(); |
| 1608 ptT = ptT->next(); | 2171 ptT = ptT->next(); |
| 1609 } while (ptT != &fPtT); | 2172 } while (ptT != &fPtT); |
| 1610 SkASSERT(this->debugCoinEndLoopCheck()); | 2173 SkASSERT(this->debugCoinEndLoopCheck()); |
| 1611 if (!this->final()) { | 2174 if (!this->final()) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1636 SkDebugf("*** bad coincident loop ***\n"); | 2199 SkDebugf("*** bad coincident loop ***\n"); |
| 1637 return false; | 2200 return false; |
| 1638 } | 2201 } |
| 1639 } | 2202 } |
| 1640 } | 2203 } |
| 1641 ++loop; | 2204 ++loop; |
| 1642 } while ((next = nextCoin) && next != this); | 2205 } while ((next = nextCoin) && next != this); |
| 1643 return true; | 2206 return true; |
| 1644 } | 2207 } |
| 1645 | 2208 |
| 2209 #if DEBUG_COINCIDENCE_VERBOSE | |
| 2210 // Commented-out lines keep this in sync with insertCoincidence() in header | |
| 2211 void SkOpSpan::debugInsertCoincidence(const char* id, SkPathOpsDebug::GlitchLog* log, const SkOpSpan* coin) const { | |
| 2212 if (containsCoincidence(coin)) { | |
| 2213 // SkASSERT(coin->containsCoincidence(this)); | |
| 2214 return; | |
| 2215 } | |
| 2216 debugValidate(); | |
| 2217 // SkASSERT(this != coin); | |
| 2218 log->record(kMarkCoinStart_Glitch, id, this, coin); | |
| 2219 // coin->fCoincident = this->fCoincident; | |
| 2220 // this->fCoincident = coinNext; | |
| 2221 debugValidate(); | |
| 2222 } | |
| 2223 | |
| 2224 // Commented-out lines keep this in sync with insertCoincidence() | |
| 2225 void SkOpSpan::debugInsertCoincidence(const char* id, SkPathOpsDebug::GlitchLog* log, const SkOpSegment* segment, bool flipped) const { | |
| 2226 if (this->containsCoincidence(segment)) { | |
| 2227 return; | |
| 2228 } | |
| 2229 const SkOpPtT* next = &fPtT; | |
| 2230 while ((next = next->next()) != &fPtT) { | |
| 2231 if (next->segment() == segment) { | |
| 2232 log->record(kMarkCoinInsert_Glitch, id, flipped ? next->span()->prev () : next->span()); | |
| 2233 return; | |
| 2234 } | |
| 2235 } | |
| 2236 #if DEBUG_COINCIDENCE | |
| 2237 log->record(kMarkCoinMissing_Glitch, id, segment, this); | |
| 2238 #endif | |
| 2239 } | |
| 2240 #endif | |
| 2241 | |
| 1646 // called only by test code | 2242 // called only by test code |
| 1647 int SkIntersections::debugCoincidentUsed() const { | 2243 int SkIntersections::debugCoincidentUsed() const { |
| 1648 if (!fIsCoincident[0]) { | 2244 if (!fIsCoincident[0]) { |
| 1649 SkASSERT(!fIsCoincident[1]); | 2245 SkASSERT(!fIsCoincident[1]); |
| 1650 return 0; | 2246 return 0; |
| 1651 } | 2247 } |
| 1652 int count = 0; | 2248 int count = 0; |
| 1653 SkDEBUGCODE(int count2 = 0;) | 2249 SkDEBUGCODE(int count2 = 0;) |
| 1654 for (int index = 0; index < fUsed; ++index) { | 2250 for (int index = 0; index < fUsed; ++index) { |
| 1655 if (fIsCoincident[0] & (1 << index)) { | 2251 if (fIsCoincident[0] & (1 << index)) { |
| 1656 ++count; | 2252 ++count; |
| 1657 } | 2253 } |
| 1658 #ifdef SK_DEBUG | 2254 #ifdef SK_DEBUG |
| 1659 if (fIsCoincident[1] & (1 << index)) { | 2255 if (fIsCoincident[1] & (1 << index)) { |
| 1660 ++count2; | 2256 ++count2; |
| 1661 } | 2257 } |
| 1662 #endif | 2258 #endif |
| 1663 } | 2259 } |
| 1664 SkASSERT(count == count2); | 2260 SkASSERT(count == count2); |
| 1665 return count; | 2261 return count; |
| 1666 } | 2262 } |
| 1667 | 2263 |
| 1668 #include "SkOpContour.h" | 2264 #include "SkOpContour.h" |
| 1669 | 2265 |
| 2266 // Commented-out lines keep this in sync with addOpp() | |
| 2267 bool SkOpPtT::debugAddOpp(const SkOpPtT* opp) const { | |
| 2268 // find the fOpp ptr to opp | |
| 2269 const SkOpPtT* oppPrev = opp->fNext; | |
| 2270 if (oppPrev == this) { | |
| 2271 return false; | |
| 2272 } | |
| 2273 while (oppPrev->fNext != opp) { | |
| 2274 oppPrev = oppPrev->fNext; | |
| 2275 if (oppPrev == this) { | |
| 2276 return false; | |
| 2277 } | |
| 2278 } | |
| 2279 // const SkOpPtT* oldNext = this->fNext; | |
| 2280 SkASSERT(this != opp); | |
| 2281 // this->fNext = opp; | |
| 2282 // SkASSERT(oppPrev != oldNext); | |
| 2283 // oppPrev->fNext = oldNext; | |
| 2284 return true; | |
| 2285 } | |
| 2286 | |
| 1670 bool SkOpPtT::debugContains(const SkOpPtT* check) const { | 2287 bool SkOpPtT::debugContains(const SkOpPtT* check) const { |
| 1671 SkASSERT(this != check); | 2288 SkASSERT(this != check); |
| 1672 const SkOpPtT* ptT = this; | 2289 const SkOpPtT* ptT = this; |
| 1673 int links = 0; | 2290 int links = 0; |
| 1674 do { | 2291 do { |
| 1675 ptT = ptT->next(); | 2292 ptT = ptT->next(); |
| 1676 if (ptT == check) { | 2293 if (ptT == check) { |
| 1677 return true; | 2294 return true; |
| 1678 } | 2295 } |
| 1679 ++links; | 2296 ++links; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1729 // -- and it's likely that a large loop count is indicative of a bug som ewhere | 2346 // -- and it's likely that a large loop count is indicative of a bug som ewhere |
| 1730 if (++loop > 1000) { | 2347 if (++loop > 1000) { |
| 1731 SkDebugf("*** loop count exceeds 1000 ***\n"); | 2348 SkDebugf("*** loop count exceeds 1000 ***\n"); |
| 1732 return 1000; | 2349 return 1000; |
| 1733 } | 2350 } |
| 1734 } while ((next = next->fNext) && next != this); | 2351 } while ((next = next->fNext) && next != this); |
| 1735 return 0; | 2352 return 0; |
| 1736 } | 2353 } |
| 1737 | 2354 |
| 1738 void SkOpPtT::debugValidate() const { | 2355 void SkOpPtT::debugValidate() const { |
| 2356 #if DEBUG_COINCIDENCE | |
| 2357 if (this->globalState()->debugCheckHealth()) { | |
| 2358 return; | |
| 2359 } | |
| 2360 #endif | |
| 1739 #if DEBUG_VALIDATE | 2361 #if DEBUG_VALIDATE |
| 1740 SkOpGlobalState::Phase phase = contour()->globalState()->phase(); | 2362 SkOpGlobalState::Phase phase = contour()->globalState()->phase(); |
| 1741 if (phase == SkOpGlobalState::kIntersecting | 2363 if (phase == SkOpGlobalState::kIntersecting |
| 1742 || phase == SkOpGlobalState::kFixWinding) { | 2364 || phase == SkOpGlobalState::kFixWinding) { |
| 1743 return; | 2365 return; |
| 1744 } | 2366 } |
| 1745 SkASSERT(fNext); | 2367 SkASSERT(fNext); |
| 1746 SkASSERT(fNext != this); | 2368 SkASSERT(fNext != this); |
| 1747 SkASSERT(fNext->fNext); | 2369 SkASSERT(fNext->fNext); |
| 1748 SkASSERT(debugLoopLimit(false) == 0); | 2370 SkASSERT(debugLoopLimit(false) == 0); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1845 #endif | 2467 #endif |
| 1846 SkPath::FillType fillType = path.getFillType(); | 2468 SkPath::FillType fillType = path.getFillType(); |
| 1847 SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInver seEvenOdd_FillType); | 2469 SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInver seEvenOdd_FillType); |
| 1848 if (includeDeclaration) { | 2470 if (includeDeclaration) { |
| 1849 SkDebugf(" SkPath %s;\n", name); | 2471 SkDebugf(" SkPath %s;\n", name); |
| 1850 } | 2472 } |
| 1851 SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]); | 2473 SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]); |
| 1852 iter.setPath(path); | 2474 iter.setPath(path); |
| 1853 showPathContours(iter, name); | 2475 showPathContours(iter, name); |
| 1854 } | 2476 } |
| OLD | NEW |