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 "SkPathOpsDebug.h" | 8 #include "SkPathOpsDebug.h" |
9 #include "SkPath.h" | 9 #include "SkPath.h" |
| 10 #if DEBUG_ANGLE |
| 11 #include "SkString.h" |
| 12 #endif |
| 13 |
| 14 #if DEBUG_VALIDATE |
| 15 extern bool FLAGS_runFail; |
| 16 #endif |
10 | 17 |
11 #if defined SK_DEBUG || !FORCE_RELEASE | 18 #if defined SK_DEBUG || !FORCE_RELEASE |
12 | 19 |
13 const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; | 20 const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; |
14 | 21 |
15 #if defined(SK_DEBUG) || !FORCE_RELEASE | 22 #if defined(SK_DEBUG) || !FORCE_RELEASE |
16 int SkPathOpsDebug::gContourID = 0; | 23 int SkPathOpsDebug::gContourID = 0; |
17 int SkPathOpsDebug::gSegmentID = 0; | 24 int SkPathOpsDebug::gSegmentID = 0; |
18 #endif | 25 #endif |
19 | 26 |
20 #if DEBUG_SORT || DEBUG_SWAP_TOP | 27 #if DEBUG_SORT || DEBUG_SWAP_TOP |
21 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; | 28 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; |
22 int SkPathOpsDebug::gSortCount; | 29 int SkPathOpsDebug::gSortCount; |
23 #endif | 30 #endif |
24 | 31 |
25 #if DEBUG_ACTIVE_OP | 32 #if DEBUG_ACTIVE_OP |
26 const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"}; | 33 const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"}; |
27 #endif | 34 #endif |
28 | 35 |
29 bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpan *>& chaseArray, | 36 bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray, |
30 const SkOpSpan* span) { | 37 const SkOpSpanBase* span) { |
31 for (int index = 0; index < chaseArray.count(); ++index) { | 38 for (int index = 0; index < chaseArray.count(); ++index) { |
32 const SkOpSpan* entry = chaseArray[index]; | 39 const SkOpSpanBase* entry = chaseArray[index]; |
33 if (entry == span) { | 40 if (entry == span) { |
34 return true; | 41 return true; |
35 } | 42 } |
36 } | 43 } |
37 return false; | 44 return false; |
38 } | 45 } |
39 | 46 |
40 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { | 47 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { |
41 size_t len = strlen(str); | 48 size_t len = strlen(str); |
42 bool num = false; | 49 bool num = false; |
(...skipping 15 matching lines...) Expand all Loading... |
58 return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; | 65 return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; |
59 } | 66 } |
60 | 67 |
61 void SkPathOpsDebug::WindingPrintf(int wind) { | 68 void SkPathOpsDebug::WindingPrintf(int wind) { |
62 if (wind == SK_MinS32) { | 69 if (wind == SK_MinS32) { |
63 SkDebugf("?"); | 70 SkDebugf("?"); |
64 } else { | 71 } else { |
65 SkDebugf("%d", wind); | 72 SkDebugf("%d", wind); |
66 } | 73 } |
67 } | 74 } |
| 75 #endif // defined SK_DEBUG || !FORCE_RELEASE |
| 76 |
68 | 77 |
69 #if DEBUG_SHOW_TEST_NAME | 78 #if DEBUG_SHOW_TEST_NAME |
70 void* SkPathOpsDebug::CreateNameStr() { | 79 void* SkPathOpsDebug::CreateNameStr() { |
71 return SkNEW_ARRAY(char, DEBUG_FILENAME_STRING_LENGTH); | 80 return SkNEW_ARRAY(char, DEBUG_FILENAME_STRING_LENGTH); |
72 } | 81 } |
73 | 82 |
74 void SkPathOpsDebug::DeleteNameStr(void* v) { | 83 void SkPathOpsDebug::DeleteNameStr(void* v) { |
75 SkDELETE_ARRAY(reinterpret_cast<char* >(v)); | 84 SkDELETE_ARRAY(reinterpret_cast<char* >(v)); |
76 } | 85 } |
77 | 86 |
(...skipping 12 matching lines...) Expand all Loading... |
90 ++dec; | 99 ++dec; |
91 SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec); | 100 SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec); |
92 } | 101 } |
93 #endif | 102 #endif |
94 | 103 |
95 #if !DEBUG_SHOW_TEST_NAME // enable when building without extended test | 104 #if !DEBUG_SHOW_TEST_NAME // enable when building without extended test |
96 void SkPathOpsDebug::ShowPath(const SkPath& one, const SkPath& two, SkPathOp op,
const char* name) { | 105 void SkPathOpsDebug::ShowPath(const SkPath& one, const SkPath& two, SkPathOp op,
const char* name) { |
97 } | 106 } |
98 #endif | 107 #endif |
99 | 108 |
100 #endif // defined SK_DEBUG || !FORCE_RELEASE | |
101 | |
102 #include "SkOpAngle.h" | 109 #include "SkOpAngle.h" |
103 #include "SkOpSegment.h" | 110 #include "SkOpSegment.h" |
104 | 111 |
| 112 #if DEBUG_SWAP_TOP |
| 113 int SkOpSegment::debugInflections(const SkOpSpanBase* start, const SkOpSpanBase*
end) const { |
| 114 if (fVerb != SkPath::kCubic_Verb) { |
| 115 return false; |
| 116 } |
| 117 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); |
| 118 double inflections[2]; |
| 119 return dst.findInflections(inflections); |
| 120 } |
| 121 #endif |
| 122 |
| 123 SkOpAngle* SkOpSegment::debugLastAngle() { |
| 124 SkOpAngle* result = NULL; |
| 125 SkOpSpan* span = this->head(); |
| 126 do { |
| 127 if (span->toAngle()) { |
| 128 SkASSERT(!result); |
| 129 result = span->toAngle(); |
| 130 } |
| 131 } while ((span = span->next()->upCastable())); |
| 132 SkASSERT(result); |
| 133 return result; |
| 134 } |
| 135 |
| 136 void SkOpSegment::debugReset() { |
| 137 this->init(this->fPts, this->contour(), this->verb()); |
| 138 } |
| 139 |
| 140 #if DEBUG_ACTIVE_SPANS |
| 141 void SkOpSegment::debugShowActiveSpans() const { |
| 142 debugValidate(); |
| 143 if (done()) { |
| 144 return; |
| 145 } |
| 146 int lastId = -1; |
| 147 double lastT = -1; |
| 148 const SkOpSpan* span = &fHead; |
| 149 do { |
| 150 if (span->done()) { |
| 151 continue; |
| 152 } |
| 153 if (lastId == fID && lastT == span->t()) { |
| 154 continue; |
| 155 } |
| 156 lastId = fID; |
| 157 lastT = span->t(); |
| 158 SkDebugf("%s id=%d", __FUNCTION__, fID); |
| 159 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
| 160 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 161 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); |
| 162 } |
| 163 const SkOpPtT* ptT = span->ptT(); |
| 164 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY); |
| 165 SkDebugf(" tEnd=%1.9g", span->next()->t()); |
| 166 SkDebugf(" windSum="); |
| 167 if (span->windSum() == SK_MinS32) { |
| 168 SkDebugf("?"); |
| 169 } else { |
| 170 SkDebugf("%d", span->windSum()); |
| 171 } |
| 172 SkDebugf(" windValue=%d oppValue=%d", span->windValue(), span->oppValue(
)); |
| 173 SkDebugf("\n"); |
| 174 } while ((span = span->next()->upCastable())); |
| 175 } |
| 176 #endif |
| 177 |
| 178 #if DEBUG_MARK_DONE |
| 179 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int
winding) { |
| 180 const SkPoint& pt = span->ptT()->fPt; |
| 181 SkDebugf("%s id=%d", fun, fID); |
| 182 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
| 183 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 184 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); |
| 185 } |
| 186 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", |
| 187 span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t()); |
| 188 if (winding == SK_MinS32) { |
| 189 SkDebugf("?"); |
| 190 } else { |
| 191 SkDebugf("%d", winding); |
| 192 } |
| 193 SkDebugf(" windSum="); |
| 194 if (span->windSum() == SK_MinS32) { |
| 195 SkDebugf("?"); |
| 196 } else { |
| 197 SkDebugf("%d", span->windSum()); |
| 198 } |
| 199 SkDebugf(" windValue=%d\n", span->windValue()); |
| 200 } |
| 201 |
| 202 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int
winding, |
| 203 int oppWinding) { |
| 204 const SkPoint& pt = span->ptT()->fPt; |
| 205 SkDebugf("%s id=%d", fun, fID); |
| 206 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
| 207 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 208 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); |
| 209 } |
| 210 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", |
| 211 span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding
, oppWinding); |
| 212 if (winding == SK_MinS32) { |
| 213 SkDebugf("?"); |
| 214 } else { |
| 215 SkDebugf("%d", winding); |
| 216 } |
| 217 SkDebugf(" newOppSum="); |
| 218 if (oppWinding == SK_MinS32) { |
| 219 SkDebugf("?"); |
| 220 } else { |
| 221 SkDebugf("%d", oppWinding); |
| 222 } |
| 223 SkDebugf(" oppSum="); |
| 224 if (span->oppSum() == SK_MinS32) { |
| 225 SkDebugf("?"); |
| 226 } else { |
| 227 SkDebugf("%d", span->oppSum()); |
| 228 } |
| 229 SkDebugf(" windSum="); |
| 230 if (span->windSum() == SK_MinS32) { |
| 231 SkDebugf("?"); |
| 232 } else { |
| 233 SkDebugf("%d", span->windSum()); |
| 234 } |
| 235 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue())
; |
| 236 } |
| 237 |
| 238 #endif |
| 239 |
| 240 #if DEBUG_ANGLE |
| 241 SkString SkOpAngle::debugPart() const { |
| 242 SkString result; |
| 243 switch (this->segment()->verb()) { |
| 244 case SkPath::kLine_Verb: |
| 245 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart), |
| 246 this->segment()->debugID()); |
| 247 break; |
| 248 case SkPath::kQuad_Verb: |
| 249 result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fCurvePart), |
| 250 this->segment()->debugID()); |
| 251 break; |
| 252 case SkPath::kCubic_Verb: |
| 253 result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fCurvePart)
, |
| 254 this->segment()->debugID()); |
| 255 break; |
| 256 default: |
| 257 SkASSERT(0); |
| 258 } |
| 259 return result; |
| 260 } |
| 261 #endif |
| 262 |
105 #if DEBUG_SORT | 263 #if DEBUG_SORT |
106 void SkOpAngle::debugLoop() const { | 264 void SkOpAngle::debugLoop() const { |
107 const SkOpAngle* first = this; | 265 const SkOpAngle* first = this; |
108 const SkOpAngle* next = this; | 266 const SkOpAngle* next = this; |
109 do { | 267 do { |
110 next->dumpOne(true); | 268 next->dumpOne(true); |
111 SkDebugf("\n"); | 269 SkDebugf("\n"); |
112 next = next->fNext; | 270 next = next->fNext; |
113 } while (next && next != first); | 271 } while (next && next != first); |
114 } | 272 next = first; |
115 #endif | 273 do { |
116 | 274 next->debugValidate(); |
117 #if DEBUG_ANGLE | 275 next = next->fNext; |
118 void SkOpAngle::debugSameAs(const SkOpAngle* compare) const { | 276 } while (next && next != first); |
119 SK_ALWAYSBREAK(fSegment == compare->fSegment); | 277 } |
120 const SkOpSpan& startSpan = fSegment->span(fStart); | 278 #endif |
121 const SkOpSpan& oStartSpan = fSegment->span(compare->fStart); | 279 |
122 SK_ALWAYSBREAK(startSpan.fToAngle == oStartSpan.fToAngle); | 280 void SkOpAngle::debugValidate() const { |
123 SK_ALWAYSBREAK(startSpan.fFromAngle == oStartSpan.fFromAngle); | |
124 const SkOpSpan& endSpan = fSegment->span(fEnd); | |
125 const SkOpSpan& oEndSpan = fSegment->span(compare->fEnd); | |
126 SK_ALWAYSBREAK(endSpan.fToAngle == oEndSpan.fToAngle); | |
127 SK_ALWAYSBREAK(endSpan.fFromAngle == oEndSpan.fFromAngle); | |
128 } | |
129 #endif | |
130 | |
131 #if DEBUG_VALIDATE | 281 #if DEBUG_VALIDATE |
| 282 const SkOpAngle* first = this; |
| 283 const SkOpAngle* next = this; |
| 284 int wind = 0; |
| 285 int opp = 0; |
| 286 int lastXor = -1; |
| 287 int lastOppXor = -1; |
| 288 do { |
| 289 if (next->unorderable()) { |
| 290 return; |
| 291 } |
| 292 const SkOpSpan* minSpan = next->start()->starter(next->end()); |
| 293 if (minSpan->windValue() == SK_MinS32) { |
| 294 return; |
| 295 } |
| 296 bool op = next->segment()->operand(); |
| 297 bool isXor = next->segment()->isXor(); |
| 298 bool oppXor = next->segment()->oppXor(); |
| 299 SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG
_LIMIT_WIND_SUM)); |
| 300 SkASSERT(!DEBUG_LIMIT_WIND_SUM |
| 301 || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIM
IT_WIND_SUM)); |
| 302 bool useXor = op ? oppXor : isXor; |
| 303 SkASSERT(lastXor == -1 || lastXor == (int) useXor); |
| 304 lastXor = (int) useXor; |
| 305 wind += next->sign() * (op ? minSpan->oppValue() : minSpan->windValue())
; |
| 306 if (useXor) { |
| 307 wind &= 1; |
| 308 } |
| 309 useXor = op ? isXor : oppXor; |
| 310 SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor); |
| 311 lastOppXor = (int) useXor; |
| 312 opp += next->sign() * (op ? minSpan->windValue() : minSpan->oppValue()); |
| 313 if (useXor) { |
| 314 opp &= 1; |
| 315 } |
| 316 next = next->fNext; |
| 317 } while (next && next != first); |
| 318 SkASSERT(wind == 0); |
| 319 SkASSERT(opp == 0 || !FLAGS_runFail); |
| 320 #endif |
| 321 } |
| 322 |
132 void SkOpAngle::debugValidateNext() const { | 323 void SkOpAngle::debugValidateNext() const { |
| 324 #if !FORCE_RELEASE |
133 const SkOpAngle* first = this; | 325 const SkOpAngle* first = this; |
134 const SkOpAngle* next = first; | 326 const SkOpAngle* next = first; |
135 SkTDArray<const SkOpAngle*>(angles); | 327 SkTDArray<const SkOpAngle*>(angles); |
136 do { | 328 do { |
137 // SK_ALWAYSBREAK(next->fSegment->debugContains(next)); | 329 // SK_ALWAYSBREAK(next->fSegment->debugContains(next)); |
138 angles.push(next); | 330 angles.push(next); |
139 next = next->next(); | 331 next = next->next(); |
140 if (next == first) { | 332 if (next == first) { |
141 break; | 333 break; |
142 } | 334 } |
143 SK_ALWAYSBREAK(!angles.contains(next)); | 335 SK_ALWAYSBREAK(!angles.contains(next)); |
144 if (!next) { | 336 if (!next) { |
145 return; | 337 return; |
146 } | 338 } |
147 } while (true); | 339 } while (true); |
148 } | 340 #endif |
149 | 341 } |
150 void SkOpAngle::debugValidateLoop() const { | 342 |
151 const SkOpAngle* first = this; | 343 void SkOpSegment::debugValidate() const { |
152 const SkOpAngle* next = first; | 344 #if DEBUG_VALIDATE |
153 SK_ALWAYSBREAK(first->next() != first); | 345 const SkOpSpanBase* span = &fHead; |
154 int signSum = 0; | 346 double lastT = -1; |
155 int oppSum = 0; | 347 const SkOpSpanBase* prev = NULL; |
156 bool firstOperand = fSegment->operand(); | 348 int count = 0; |
157 bool unorderable = false; | 349 int done = 0; |
158 do { | 350 do { |
159 unorderable |= next->fUnorderable; | 351 if (!span->final()) { |
160 const SkOpSegment* segment = next->fSegment; | 352 ++count; |
161 bool operandsMatch = firstOperand == segment->operand(); | 353 done += span->upCast()->done() ? 1 : 0; |
162 signSum += operandsMatch ? segment->spanSign(next) : segment->oppSign(ne
xt); | 354 } |
163 oppSum += operandsMatch ? segment->oppSign(next) : segment->spanSign(nex
t); | 355 SkASSERT(span->segment() == this); |
164 const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 356 SkASSERT(!prev || prev->upCast()->next() == span); |
165 if (segment->_xor()) { | 357 SkASSERT(!prev || prev == span->prev()); |
166 // SK_ALWAYSBREAK(span.fWindValue == 1); | 358 prev = span; |
167 // SK_ALWAYSBREAK(span.fWindSum == SK_MinS32 || span.fWindSum == 1); | 359 double t = span->ptT()->fT; |
168 } | 360 SkASSERT(lastT < t); |
169 if (segment->oppXor()) { | 361 lastT = t; |
170 SK_ALWAYSBREAK(span.fOppValue == 0 || abs(span.fOppValue) == 1); | 362 span->debugValidate(); |
171 // SK_ALWAYSBREAK(span.fOppSum == SK_MinS32 || span.fOppSum == 0 || a
bs(span.fOppSum) == 1); | 363 } while (!span->final() && (span = span->upCast()->next())); |
172 } | 364 SkASSERT(count == fCount); |
173 next = next->next(); | 365 SkASSERT(done == fDoneCount); |
174 if (!next) { | 366 SkASSERT(span->final()); |
175 return; | 367 span->debugValidate(); |
176 } | 368 #endif |
177 } while (next != first); | 369 } |
178 if (unorderable) { | 370 |
179 return; | 371 bool SkOpSpanBase::debugCoinEndLoopCheck() const { |
180 } | 372 int loop = 0; |
181 SK_ALWAYSBREAK(!signSum || fSegment->_xor()); | 373 const SkOpSpanBase* next = this; |
182 SK_ALWAYSBREAK(!oppSum || fSegment->oppXor()); | 374 SkOpSpanBase* nextCoin; |
183 int lastWinding; | 375 do { |
184 int lastOppWinding; | 376 nextCoin = next->fCoinEnd; |
185 int winding; | 377 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); |
186 int oppWinding; | 378 for (int check = 1; check < loop - 1; ++check) { |
187 do { | 379 const SkOpSpanBase* checkCoin = this->fCoinEnd; |
188 const SkOpSegment* segment = next->fSegment; | 380 const SkOpSpanBase* innerCoin = checkCoin; |
189 const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 381 for (int inner = check + 1; inner < loop; ++inner) { |
190 winding = span.fWindSum; | 382 innerCoin = innerCoin->fCoinEnd; |
191 if (winding != SK_MinS32) { | 383 if (checkCoin == innerCoin) { |
192 // SK_ALWAYSBREAK(winding != 0); | 384 SkDebugf("*** bad coincident end loop ***\n"); |
193 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 385 return false; |
194 lastWinding = winding; | |
195 int diffWinding = segment->spanSign(next); | |
196 if (!segment->_xor()) { | |
197 SK_ALWAYSBREAK(diffWinding != 0); | |
198 bool sameSign = (winding > 0) == (diffWinding > 0); | |
199 winding -= sameSign ? diffWinding : -diffWinding; | |
200 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | |
201 SK_ALWAYSBREAK(abs(winding) <= abs(lastWinding)); | |
202 if (!sameSign) { | |
203 SkTSwap(winding, lastWinding); | |
204 } | 386 } |
205 } | 387 } |
206 lastOppWinding = oppWinding = span.fOppSum; | 388 } |
207 if (oppWinding != SK_MinS32 && !segment->oppXor()) { | 389 ++loop; |
208 int oppDiffWinding = segment->oppSign(next); | 390 } while ((next = nextCoin) && next != this); |
209 // SK_ALWAYSBREAK(abs(oppDiffWinding) <= abs(diffWinding) || segm
ent->_xor()); | 391 return true; |
210 if (oppDiffWinding) { | 392 } |
211 bool oppSameSign = (oppWinding > 0) == (oppDiffWinding > 0); | 393 |
212 oppWinding -= oppSameSign ? oppDiffWinding : -oppDiffWinding
; | 394 void SkOpSpanBase::debugValidate() const { |
213 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 395 #if DEBUG_VALIDATE |
214 SK_ALWAYSBREAK(abs(oppWinding) <= abs(lastOppWinding)); | 396 const SkOpPtT* ptT = &fPtT; |
215 if (!oppSameSign) { | 397 SkASSERT(ptT->span() == this); |
216 SkTSwap(oppWinding, lastOppWinding); | 398 do { |
217 } | 399 // SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); |
| 400 ptT->debugValidate(); |
| 401 ptT = ptT->next(); |
| 402 } while (ptT != &fPtT); |
| 403 SkASSERT(this->debugCoinEndLoopCheck()); |
| 404 if (!this->final()) { |
| 405 SkASSERT(this->upCast()->debugCoinLoopCheck()); |
| 406 } |
| 407 if (fFromAngle) { |
| 408 fFromAngle->debugValidate(); |
| 409 } |
| 410 if (!this->final() && this->upCast()->toAngle()) { |
| 411 this->upCast()->toAngle()->debugValidate(); |
| 412 } |
| 413 #endif |
| 414 } |
| 415 |
| 416 bool SkOpSpan::debugCoinLoopCheck() const { |
| 417 int loop = 0; |
| 418 const SkOpSpan* next = this; |
| 419 SkOpSpan* nextCoin; |
| 420 do { |
| 421 nextCoin = next->fCoincident; |
| 422 SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin); |
| 423 for (int check = 1; check < loop - 1; ++check) { |
| 424 const SkOpSpan* checkCoin = this->fCoincident; |
| 425 const SkOpSpan* innerCoin = checkCoin; |
| 426 for (int inner = check + 1; inner < loop; ++inner) { |
| 427 innerCoin = innerCoin->fCoincident; |
| 428 if (checkCoin == innerCoin) { |
| 429 SkDebugf("*** bad coincident loop ***\n"); |
| 430 return false; |
218 } | 431 } |
219 } | 432 } |
220 firstOperand = segment->operand(); | 433 } |
221 break; | 434 ++loop; |
222 } | 435 } while ((next = nextCoin) && next != this); |
223 SK_ALWAYSBREAK(span.fOppSum == SK_MinS32); | 436 return true; |
224 next = next->next(); | 437 } |
225 } while (next != first); | 438 |
226 if (winding == SK_MinS32) { | 439 #include "SkOpContour.h" |
227 return; | 440 |
228 } | 441 int SkOpPtT::debugLoopLimit(bool report) const { |
229 SK_ALWAYSBREAK(oppWinding == SK_MinS32 || SkPathOpsDebug::ValidWind(oppWindi
ng)); | 442 int loop = 0; |
230 first = next; | 443 const SkOpPtT* next = this; |
231 next = next->next(); | 444 do { |
232 do { | 445 for (int check = 1; check < loop - 1; ++check) { |
233 const SkOpSegment* segment = next->fSegment; | 446 const SkOpPtT* checkPtT = this->fNext; |
234 lastWinding = winding; | 447 const SkOpPtT* innerPtT = checkPtT; |
235 lastOppWinding = oppWinding; | 448 for (int inner = check + 1; inner < loop; ++inner) { |
236 bool operandsMatch = firstOperand == segment->operand(); | 449 innerPtT = innerPtT->fNext; |
237 if (operandsMatch) { | 450 if (checkPtT == innerPtT) { |
238 if (!segment->_xor()) { | 451 if (report) { |
239 winding -= segment->spanSign(next); | 452 SkDebugf("*** bad ptT loop ***\n"); |
240 SK_ALWAYSBREAK(winding != lastWinding); | 453 } |
241 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 454 return loop; |
242 } | |
243 if (!segment->oppXor()) { | |
244 int oppDiffWinding = segment->oppSign(next); | |
245 if (oppWinding != SK_MinS32) { | |
246 oppWinding -= oppDiffWinding; | |
247 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | |
248 } else { | |
249 SK_ALWAYSBREAK(oppDiffWinding == 0); | |
250 } | 455 } |
251 } | 456 } |
252 } else { | 457 } |
253 if (!segment->oppXor()) { | 458 ++loop; |
254 winding -= segment->oppSign(next); | 459 } while ((next = next->fNext) && next != this); |
255 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 460 return 0; |
256 } | 461 } |
257 if (!segment->_xor()) { | 462 |
258 oppWinding -= segment->spanSign(next); | 463 void SkOpPtT::debugValidate() const { |
259 SK_ALWAYSBREAK(oppWinding != lastOppWinding); | 464 #if DEBUG_VALIDATE |
260 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 465 if (contour()->globalState()->phase() == SkOpGlobalState::kIntersecting) { |
261 } | |
262 } | |
263 bool useInner = SkOpSegment::UseInnerWinding(lastWinding, winding); | |
264 int sumWinding = useInner ? winding : lastWinding; | |
265 bool oppUseInner = SkOpSegment::UseInnerWinding(lastOppWinding, oppWindi
ng); | |
266 int oppSumWinding = oppUseInner ? oppWinding : lastOppWinding; | |
267 if (!operandsMatch) { | |
268 SkTSwap(useInner, oppUseInner); | |
269 SkTSwap(sumWinding, oppSumWinding); | |
270 } | |
271 const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | |
272 if (winding == -lastWinding) { | |
273 if (span.fWindSum != SK_MinS32) { | |
274 SkDebugf("%s useInner=%d spanSign=%d lastWinding=%d winding=%d w
indSum=%d\n", | |
275 __FUNCTION__, | |
276 useInner, segment->spanSign(next), lastWinding, winding,
span.fWindSum); | |
277 } | |
278 } | |
279 if (oppWinding != SK_MinS32) { | |
280 if (span.fOppSum != SK_MinS32) { | |
281 SK_ALWAYSBREAK(span.fOppSum == oppSumWinding || segment->oppXor(
) || segment->_xor()); | |
282 } | |
283 } else { | |
284 SK_ALWAYSBREAK(!firstOperand); | |
285 SK_ALWAYSBREAK(!segment->operand()); | |
286 SK_ALWAYSBREAK(!span.fOppValue); | |
287 } | |
288 next = next->next(); | |
289 } while (next != first); | |
290 } | |
291 #endif | |
292 | |
293 #if DEBUG_SWAP_TOP | |
294 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { | |
295 if (fVerb != SkPath::kCubic_Verb) { | |
296 return false; | |
297 } | |
298 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
299 return dst.controlsContainedByEnds(); | |
300 } | |
301 #endif | |
302 | |
303 #if DEBUG_CONCIDENT | |
304 // SK_ALWAYSBREAK if pair has not already been added | |
305 void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double other
T) const { | |
306 for (int i = 0; i < fTs.count(); ++i) { | |
307 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == other
T) { | |
308 return; | |
309 } | |
310 } | |
311 SK_ALWAYSBREAK(0); | |
312 } | |
313 #endif | |
314 | |
315 #if DEBUG_ANGLE | |
316 void SkOpSegment::debugCheckPointsEqualish(int tStart, int tEnd) const { | |
317 const SkPoint& basePt = fTs[tStart].fPt; | |
318 while (++tStart < tEnd) { | |
319 const SkPoint& cmpPt = fTs[tStart].fPt; | |
320 SK_ALWAYSBREAK(SkDPoint::ApproximatelyEqual(basePt, cmpPt)); | |
321 } | |
322 } | |
323 #endif | |
324 | |
325 #if DEBUG_SWAP_TOP | |
326 int SkOpSegment::debugInflections(int tStart, int tEnd) const { | |
327 if (fVerb != SkPath::kCubic_Verb) { | |
328 return false; | |
329 } | |
330 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
331 double inflections[2]; | |
332 return dst.findInflections(inflections); | |
333 } | |
334 #endif | |
335 | |
336 const SkOpAngle* SkOpSegment::debugLastAngle() const { | |
337 const SkOpAngle* result = NULL; | |
338 for (int index = 0; index < count(); ++index) { | |
339 const SkOpSpan& span = this->span(index); | |
340 if (span.fToAngle) { | |
341 SkASSERT(!result); | |
342 result = span.fToAngle; | |
343 } | |
344 } | |
345 SkASSERT(result); | |
346 return result; | |
347 } | |
348 | |
349 void SkOpSegment::debugReset() { | |
350 fTs.reset(); | |
351 fAngles.reset(); | |
352 } | |
353 | |
354 #if DEBUG_CONCIDENT | |
355 void SkOpSegment::debugShowTs(const char* prefix) const { | |
356 SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID); | |
357 int lastWind = -1; | |
358 int lastOpp = -1; | |
359 double lastT = -1; | |
360 int i; | |
361 for (i = 0; i < fTs.count(); ++i) { | |
362 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue | |
363 || lastOpp != fTs[i].fOppValue; | |
364 if (change && lastWind >= 0) { | |
365 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | |
366 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | |
367 } | |
368 if (change) { | |
369 SkDebugf(" [o=%d", fTs[i].fOther->fID); | |
370 lastWind = fTs[i].fWindValue; | |
371 lastOpp = fTs[i].fOppValue; | |
372 lastT = fTs[i].fT; | |
373 } else { | |
374 SkDebugf(",%d", fTs[i].fOther->fID); | |
375 } | |
376 } | |
377 if (i <= 0) { | |
378 return; | 466 return; |
379 } | 467 } |
380 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | 468 SkASSERT(fNext); |
381 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | 469 SkASSERT(fNext != this); |
382 if (fOperand) { | 470 SkASSERT(fNext->fNext); |
383 SkDebugf(" operand"); | 471 SkASSERT(debugLoopLimit(false) == 0); |
384 } | 472 #endif |
385 if (done()) { | 473 } |
386 SkDebugf(" done"); | |
387 } | |
388 SkDebugf("\n"); | |
389 } | |
390 #endif | |
391 | |
392 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
393 void SkOpSegment::debugShowActiveSpans() const { | |
394 debugValidate(); | |
395 if (done()) { | |
396 return; | |
397 } | |
398 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | |
399 int lastId = -1; | |
400 double lastT = -1; | |
401 #endif | |
402 for (int i = 0; i < fTs.count(); ++i) { | |
403 if (fTs[i].fDone) { | |
404 continue; | |
405 } | |
406 SK_ALWAYSBREAK(i < fTs.count() - 1); | |
407 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | |
408 if (lastId == fID && lastT == fTs[i].fT) { | |
409 continue; | |
410 } | |
411 lastId = fID; | |
412 lastT = fTs[i].fT; | |
413 #endif | |
414 SkDebugf("%s id=%d", __FUNCTION__, fID); | |
415 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
416 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
417 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
418 } | |
419 const SkOpSpan* span = &fTs[i]; | |
420 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span)); | |
421 int iEnd = i + 1; | |
422 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT))
{ | |
423 ++iEnd; | |
424 } | |
425 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT); | |
426 const SkOpSegment* other = fTs[i].fOther; | |
427 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", | |
428 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); | |
429 if (fTs[i].fWindSum == SK_MinS32) { | |
430 SkDebugf("?"); | |
431 } else { | |
432 SkDebugf("%d", fTs[i].fWindSum); | |
433 } | |
434 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppVa
lue); | |
435 } | |
436 } | |
437 #endif | |
438 | |
439 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE | |
440 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
winding) { | |
441 const SkPoint& pt = xyAtT(&span); | |
442 SkDebugf("%s id=%d", fun, fID); | |
443 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
444 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
445 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
446 } | |
447 SK_ALWAYSBREAK(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | |
448 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | |
449 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=", | |
450 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.f
Y, | |
451 (&span)[1].fT, winding); | |
452 if (span.fWindSum == SK_MinS32) { | |
453 SkDebugf("?"); | |
454 } else { | |
455 SkDebugf("%d", span.fWindSum); | |
456 } | |
457 SkDebugf(" windValue=%d\n", span.fWindValue); | |
458 } | |
459 | |
460 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
winding, | |
461 int oppWinding) { | |
462 const SkPoint& pt = xyAtT(&span); | |
463 SkDebugf("%s id=%d", fun, fID); | |
464 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
465 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
466 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
467 } | |
468 SK_ALWAYSBREAK(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | |
469 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | |
470 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d
oppSum=", | |
471 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.f
Y, | |
472 (&span)[1].fT, winding, oppWinding); | |
473 if (span.fOppSum == SK_MinS32) { | |
474 SkDebugf("?"); | |
475 } else { | |
476 SkDebugf("%d", span.fOppSum); | |
477 } | |
478 SkDebugf(" windSum="); | |
479 if (span.fWindSum == SK_MinS32) { | |
480 SkDebugf("?"); | |
481 } else { | |
482 SkDebugf("%d", span.fWindSum); | |
483 } | |
484 SkDebugf(" windValue=%d oppValue=%d\n", span.fWindValue, span.fOppValue); | |
485 } | |
486 #endif | |
487 | |
488 #if DEBUG_SHOW_WINDING | |
489 int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const { | |
490 if (!(1 << fID & ofInterest)) { | |
491 return 0; | |
492 } | |
493 int sum = 0; | |
494 SkTArray<char, true> slots(slotCount * 2); | |
495 memset(slots.begin(), ' ', slotCount * 2); | |
496 for (int i = 0; i < fTs.count(); ++i) { | |
497 // if (!(1 << fTs[i].fOther->fID & ofInterest)) { | |
498 // continue; | |
499 // } | |
500 sum += fTs[i].fWindValue; | |
501 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); | |
502 sum += fTs[i].fOppValue; | |
503 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); | |
504 } | |
505 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, | |
506 slots.begin() + slotCount); | |
507 return sum; | |
508 } | |
509 #endif | |
510 | |
511 void SkOpSegment::debugValidate() const { | |
512 #if DEBUG_VALIDATE | |
513 int count = fTs.count(); | |
514 SK_ALWAYSBREAK(count >= 2); | |
515 SK_ALWAYSBREAK(fTs[0].fT == 0); | |
516 SK_ALWAYSBREAK(fTs[count - 1].fT == 1); | |
517 int done = 0; | |
518 double t = -1; | |
519 const SkOpSpan* last = NULL; | |
520 bool tinyTFound = false; | |
521 bool hasLoop = false; | |
522 for (int i = 0; i < count; ++i) { | |
523 const SkOpSpan& span = fTs[i]; | |
524 SK_ALWAYSBREAK(t <= span.fT); | |
525 t = span.fT; | |
526 int otherIndex = span.fOtherIndex; | |
527 const SkOpSegment* other = span.fOther; | |
528 SK_ALWAYSBREAK(other != this || fVerb == SkPath::kCubic_Verb); | |
529 const SkOpSpan& otherSpan = other->fTs[otherIndex]; | |
530 SK_ALWAYSBREAK(otherSpan.fPt == span.fPt); | |
531 SK_ALWAYSBREAK(otherSpan.fOtherT == t); | |
532 SK_ALWAYSBREAK(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex])
; | |
533 done += span.fDone; | |
534 if (last) { | |
535 SK_ALWAYSBREAK(last->fT != span.fT || last->fOther != span.fOther); | |
536 bool tsEqual = last->fT == span.fT; | |
537 bool tsPreciselyEqual = precisely_equal(last->fT, span.fT); | |
538 SK_ALWAYSBREAK(!tsEqual || tsPreciselyEqual); | |
539 bool pointsEqual = last->fPt == span.fPt; | |
540 bool pointsNearlyEqual = AlmostEqualUlps(last->fPt, span.fPt); | |
541 #if 0 // bufferOverflow test triggers this | |
542 SK_ALWAYSBREAK(!tsPreciselyEqual || pointsNearlyEqual); | |
543 #endif | |
544 // SK_ALWAYSBREAK(!last->fTiny || !tsPreciselyEqual || span.fTiny ||
tinyTFound); | |
545 SK_ALWAYSBREAK(last->fTiny || tsPreciselyEqual || !pointsEqual || ha
sLoop); | |
546 SK_ALWAYSBREAK(!last->fTiny || pointsEqual); | |
547 SK_ALWAYSBREAK(!last->fTiny || last->fDone); | |
548 SK_ALWAYSBREAK(!last->fSmall || pointsNearlyEqual); | |
549 SK_ALWAYSBREAK(!last->fSmall || last->fDone); | |
550 // SK_ALWAYSBREAK(!last->fSmall || last->fTiny); | |
551 // SK_ALWAYSBREAK(last->fTiny || !pointsEqual || last->fDone == span.
fDone); | |
552 if (last->fTiny) { | |
553 tinyTFound |= !tsPreciselyEqual; | |
554 } else { | |
555 tinyTFound = false; | |
556 } | |
557 } | |
558 last = &span; | |
559 hasLoop |= last->fLoop; | |
560 } | |
561 SK_ALWAYSBREAK(done == fDoneSpans); | |
562 // if (fAngles.count() ) { | |
563 // fAngles.begin()->debugValidateLoop(); | |
564 // } | |
565 #endif | |
566 } | |
OLD | NEW |