| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkIntersections.h" | 7 #include "SkOpCoincidence.h" |
| 8 #include "SkOpContour.h" | 8 #include "SkOpContour.h" |
| 9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
| 10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
| 11 #include "SkTSort.h" | 11 |
| 12 /* |
| 13 After computing raw intersections, post process all segments to: |
| 14 - find small collections of points that can be collapsed to a single point |
| 15 - find missing intersections to resolve differences caused by different algorith
ms |
| 16 |
| 17 Consider segments containing tiny or small intervals. Consider coincident segmen
ts |
| 18 because coincidence finds intersections through distance measurement that non-co
incident |
| 19 intersection tests cannot. |
| 20 */ |
| 12 | 21 |
| 13 #define F (false) // discard the edge | 22 #define F (false) // discard the edge |
| 14 #define T (true) // keep the edge | 23 #define T (true) // keep the edge |
| 15 | 24 |
| 16 static const bool gUnaryActiveEdge[2][2] = { | 25 static const bool gUnaryActiveEdge[2][2] = { |
| 17 // from=0 from=1 | 26 // from=0 from=1 |
| 18 // to=0,1 to=0,1 | 27 // to=0,1 to=0,1 |
| 19 {F, T}, {T, F}, | 28 {F, T}, {T, F}, |
| 20 }; | 29 }; |
| 21 | 30 |
| 22 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = { | 31 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = { |
| 23 // miFrom=0 miFrom=1 | 32 // miFrom=0 miFrom=1 |
| 24 // miTo=0 miTo=1 miTo=0 miTo=1 | 33 // miTo=0 miTo=1 miTo=0 miTo=1 |
| 25 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 | 34 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 |
| 26 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 | 35 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 |
| 27 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}
, // mi - su | 36 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}
, // mi - su |
| 28 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}
, // mi & su | 37 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}
, // mi & su |
| 29 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}
, // mi | su | 38 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}
, // mi | su |
| 30 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}
, // mi ^ su | 39 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}
, // mi ^ su |
| 31 }; | 40 }; |
| 32 | 41 |
| 33 #undef F | 42 #undef F |
| 34 #undef T | 43 #undef T |
| 35 | 44 |
| 36 enum { | 45 SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr
, |
| 37 kOutsideTrackedTCount = 16, // FIXME: determine what this should be | 46 SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
| 38 kMissingSpanCount = 4, // FIXME: determine what this should be | 47 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done, sort
able)) { |
| 39 }; | |
| 40 | |
| 41 const SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool*
done, | |
| 42 bool* sortable) const { | |
| 43 if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sort
able)) { | |
| 44 return result; | 48 return result; |
| 45 } | 49 } |
| 46 double referenceT = fTs[index].fT; | 50 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done, sort
able)) { |
| 47 int lesser = index; | 51 return result; |
| 48 while (--lesser >= 0 | |
| 49 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f
Tiny)) { | |
| 50 if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done,
sortable)) { | |
| 51 return result; | |
| 52 } | |
| 53 } | 52 } |
| 54 do { | |
| 55 if (const SkOpAngle* result = activeAngleOther(index, start, end, done,
sortable)) { | |
| 56 return result; | |
| 57 } | |
| 58 if (++index == fTs.count()) { | |
| 59 break; | |
| 60 } | |
| 61 if (fTs[index - 1].fTiny) { | |
| 62 referenceT = fTs[index].fT; | |
| 63 continue; | |
| 64 } | |
| 65 } while (precisely_negative(fTs[index].fT - referenceT)); | |
| 66 return NULL; | 53 return NULL; |
| 67 } | 54 } |
| 68 | 55 |
| 69 const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end,
bool* done, | 56 SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** sta
rtPtr, |
| 70 bool* sortable) const { | 57 SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
| 71 int next = nextExactSpan(index, 1); | 58 SkOpSpan* upSpan = start->upCastable(); |
| 72 if (next > 0) { | 59 if (upSpan) { |
| 73 const SkOpSpan& upSpan = fTs[index]; | 60 if (upSpan->windValue() || upSpan->oppValue()) { |
| 74 if (upSpan.fWindValue || upSpan.fOppValue) { | 61 SkOpSpanBase* next = upSpan->next(); |
| 75 if (*end < 0) { | 62 if (!*endPtr) { |
| 76 *start = index; | 63 *startPtr = start; |
| 77 *end = next; | 64 *endPtr = next; |
| 78 } | 65 } |
| 79 if (!upSpan.fDone) { | 66 if (!upSpan->done()) { |
| 80 if (upSpan.fWindSum != SK_MinS32) { | 67 if (upSpan->windSum() != SK_MinS32) { |
| 81 return spanToAngle(index, next); | 68 return spanToAngle(start, next); |
| 82 } | 69 } |
| 83 *done = false; | 70 *done = false; |
| 84 } | 71 } |
| 85 } else { | 72 } else { |
| 86 SkASSERT(upSpan.fDone); | 73 SkASSERT(upSpan->done()); |
| 87 } | 74 } |
| 88 } | 75 } |
| 89 int prev = nextExactSpan(index, -1); | 76 SkOpSpan* downSpan = start->prev(); |
| 90 // edge leading into junction | 77 // edge leading into junction |
| 91 if (prev >= 0) { | 78 if (downSpan) { |
| 92 const SkOpSpan& downSpan = fTs[prev]; | 79 if (downSpan->windValue() || downSpan->oppValue()) { |
| 93 if (downSpan.fWindValue || downSpan.fOppValue) { | 80 if (!*endPtr) { |
| 94 if (*end < 0) { | 81 *startPtr = start; |
| 95 *start = index; | 82 *endPtr = downSpan; |
| 96 *end = prev; | |
| 97 } | 83 } |
| 98 if (!downSpan.fDone) { | 84 if (!downSpan->done()) { |
| 99 if (downSpan.fWindSum != SK_MinS32) { | 85 if (downSpan->windSum() != SK_MinS32) { |
| 100 return spanToAngle(index, prev); | 86 return spanToAngle(start, downSpan); |
| 101 } | 87 } |
| 102 *done = false; | 88 *done = false; |
| 103 } | 89 } |
| 104 } else { | 90 } else { |
| 105 SkASSERT(downSpan.fDone); | 91 SkASSERT(downSpan->done()); |
| 106 } | 92 } |
| 107 } | 93 } |
| 108 return NULL; | 94 return NULL; |
| 109 } | 95 } |
| 110 | 96 |
| 111 const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end,
bool* done, | 97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta
rtPtr, |
| 112 bool* sortable) const { | 98 SkOpSpanBase** endPtr, bool* done, bool* sortable) { |
| 113 const SkOpSpan* span = &fTs[index]; | 99 SkOpPtT* oPtT = start->ptT()->next(); |
| 114 SkOpSegment* other = span->fOther; | 100 SkOpSegment* other = oPtT->segment(); |
| 115 int oIndex = span->fOtherIndex; | 101 SkOpSpanBase* oSpan = oPtT->span(); |
| 116 return other->activeAngleInner(oIndex, start, end, done, sortable); | 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); |
| 117 } | 103 } |
| 118 | 104 |
| 119 SkPoint SkOpSegment::activeLeftTop(int* firstT) const { | 105 SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { |
| 120 SkASSERT(!done()); | 106 SkASSERT(!done()); |
| 121 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; | 107 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; |
| 122 int count = fTs.count(); | |
| 123 // see if either end is not done since we want smaller Y of the pair | 108 // see if either end is not done since we want smaller Y of the pair |
| 124 bool lastDone = true; | 109 bool lastDone = true; |
| 125 double lastT = -1; | 110 double lastT = -1; |
| 126 for (int index = 0; index < count; ++index) { | 111 SkOpSpanBase* span = &fHead; |
| 127 const SkOpSpan& span = fTs[index]; | 112 do { |
| 128 if (span.fDone && lastDone) { | 113 if (lastDone && (span->final() || span->upCast()->done())) { |
| 129 goto next; | |
| 130 } | |
| 131 if (approximately_negative(span.fT - lastT)) { | |
| 132 goto next; | 114 goto next; |
| 133 } | 115 } |
| 134 { | 116 { |
| 135 const SkPoint& xy = xyAtT(&span); | 117 const SkPoint& xy = span->pt(); |
| 136 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { | 118 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { |
| 137 topPt = xy; | 119 topPt = xy; |
| 138 if (firstT) { | 120 if (firstSpan) { |
| 139 *firstT = index; | 121 *firstSpan = span; |
| 140 } | 122 } |
| 141 } | 123 } |
| 142 if (fVerb != SkPath::kLine_Verb && !lastDone) { | 124 if (fVerb != SkPath::kLine_Verb && !lastDone) { |
| 143 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPt
s, lastT, span.fT); | 125 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPt
s, lastT, |
| 126 span->t()); |
| 144 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY | 127 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY |
| 145 && topPt.fX > curveTop.fX)) { | 128 && topPt.fX > curveTop.fX)) { |
| 146 topPt = curveTop; | 129 topPt = curveTop; |
| 147 if (firstT) { | 130 if (firstSpan) { |
| 148 *firstT = index; | 131 *firstSpan = span; |
| 149 } | 132 } |
| 150 } | 133 } |
| 151 } | 134 } |
| 152 lastT = span.fT; | 135 lastT = span->t(); |
| 153 } | 136 } |
| 154 next: | 137 next: |
| 155 lastDone = span.fDone; | 138 if (span->final()) { |
| 156 } | 139 break; |
| 140 } |
| 141 lastDone = span->upCast()->done(); |
| 142 } while ((span = span->upCast()->next())); |
| 157 return topPt; | 143 return topPt; |
| 158 } | 144 } |
| 159 | 145 |
| 160 bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask
, SkPathOp op) { | 146 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask
, int xorSuMask, |
| 161 int sumMiWinding = updateWinding(endIndex, index); | 147 SkPathOp op) { |
| 162 int sumSuWinding = updateOppWinding(endIndex, index); | 148 int sumMiWinding = this->updateWinding(end, start); |
| 149 int sumSuWinding = this->updateOppWinding(end, start); |
| 163 #if DEBUG_LIMIT_WIND_SUM | 150 #if DEBUG_LIMIT_WIND_SUM |
| 164 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); | 151 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); |
| 165 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); | 152 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); |
| 166 #endif | 153 #endif |
| 167 if (fOperand) { | 154 if (this->operand()) { |
| 168 SkTSwap<int>(sumMiWinding, sumSuWinding); | 155 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 169 } | 156 } |
| 170 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &s
umSuWinding); | 157 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &
sumSuWinding); |
| 171 } | 158 } |
| 172 | 159 |
| 173 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex
, SkPathOp op, | 160 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, Sk
OpSpanBase* end, |
| 174 int* sumMiWinding, int* sumSuWinding) { | 161 SkPathOp op, int* sumMiWinding, int* sumSuWinding) { |
| 175 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | 162 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; |
| 176 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding, | 163 this->setUpWindings(start, end, sumMiWinding, sumSuWinding, |
| 177 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | 164 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
| 178 bool miFrom; | 165 bool miFrom; |
| 179 bool miTo; | 166 bool miTo; |
| 180 bool suFrom; | 167 bool suFrom; |
| 181 bool suTo; | 168 bool suTo; |
| 182 if (operand()) { | 169 if (operand()) { |
| 183 miFrom = (oppMaxWinding & xorMiMask) != 0; | 170 miFrom = (oppMaxWinding & xorMiMask) != 0; |
| 184 miTo = (oppSumWinding & xorMiMask) != 0; | 171 miTo = (oppSumWinding & xorMiMask) != 0; |
| 185 suFrom = (maxWinding & xorSuMask) != 0; | 172 suFrom = (maxWinding & xorSuMask) != 0; |
| 186 suTo = (sumWinding & xorSuMask) != 0; | 173 suTo = (sumWinding & xorSuMask) != 0; |
| 187 } else { | 174 } else { |
| 188 miFrom = (maxWinding & xorMiMask) != 0; | 175 miFrom = (maxWinding & xorMiMask) != 0; |
| 189 miTo = (sumWinding & xorMiMask) != 0; | 176 miTo = (sumWinding & xorMiMask) != 0; |
| 190 suFrom = (oppMaxWinding & xorSuMask) != 0; | 177 suFrom = (oppMaxWinding & xorSuMask) != 0; |
| 191 suTo = (oppSumWinding & xorSuMask) != 0; | 178 suTo = (oppSumWinding & xorSuMask) != 0; |
| 192 } | 179 } |
| 193 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; | 180 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; |
| 194 #if DEBUG_ACTIVE_OP | 181 #if DEBUG_ACTIVE_OP |
| 195 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo
=%d result=%d\n", | 182 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo
=%d result=%d\n", |
| 196 __FUNCTION__, debugID(), span(index).fT, span(endIndex).fT, | 183 __FUNCTION__, debugID(), start->t(), end->t(), |
| 197 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); | 184 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); |
| 198 #endif | 185 #endif |
| 199 return result; | 186 return result; |
| 200 } | 187 } |
| 201 | 188 |
| 202 bool SkOpSegment::activeWinding(int index, int endIndex) { | 189 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) { |
| 203 int sumWinding = updateWinding(endIndex, index); | 190 int sumWinding = updateWinding(end, start); |
| 204 return activeWinding(index, endIndex, &sumWinding); | 191 return activeWinding(start, end, &sumWinding); |
| 205 } | 192 } |
| 206 | 193 |
| 207 bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) { | 194 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
Winding) { |
| 208 int maxWinding; | 195 int maxWinding; |
| 209 setUpWinding(index, endIndex, &maxWinding, sumWinding); | 196 setUpWinding(start, end, &maxWinding, sumWinding); |
| 210 bool from = maxWinding != 0; | 197 bool from = maxWinding != 0; |
| 211 bool to = *sumWinding != 0; | 198 bool to = *sumWinding != 0; |
| 212 bool result = gUnaryActiveEdge[from][to]; | 199 bool result = gUnaryActiveEdge[from][to]; |
| 213 return result; | 200 return result; |
| 214 } | 201 } |
| 215 | 202 |
| 216 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt
, | 203 void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 217 SkOpSegment* other) { | 204 SkPathWriter* path, bool active) const { |
| 218 int tIndex = -1; | |
| 219 int tCount = fTs.count(); | |
| 220 int oIndex = -1; | |
| 221 int oCount = other->fTs.count(); | |
| 222 do { | |
| 223 ++tIndex; | |
| 224 } while (startPt != fTs[tIndex].fPt && tIndex < tCount); | |
| 225 int tIndexStart = tIndex; | |
| 226 do { | |
| 227 ++oIndex; | |
| 228 } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount); | |
| 229 int oIndexStart = oIndex; | |
| 230 const SkPoint* nextPt; | |
| 231 do { | |
| 232 nextPt = &fTs[++tIndex].fPt; | |
| 233 SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt); | |
| 234 } while (startPt == *nextPt); | |
| 235 double nextT = fTs[tIndex].fT; | |
| 236 const SkPoint* oNextPt; | |
| 237 do { | |
| 238 oNextPt = &other->fTs[++oIndex].fPt; | |
| 239 SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt); | |
| 240 } while (endPt == *oNextPt); | |
| 241 double oNextT = other->fTs[oIndex].fT; | |
| 242 // at this point, spans before and after are at: | |
| 243 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex] | |
| 244 // if tIndexStart == 0, no prior span | |
| 245 // if nextT == 1, no following span | |
| 246 | |
| 247 // advance the span with zero winding | |
| 248 // if the following span exists (not past the end, non-zero winding) | |
| 249 // connect the two edges | |
| 250 if (!fTs[tIndexStart].fWindValue) { | |
| 251 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) { | |
| 252 #if DEBUG_CONCIDENT | |
| 253 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", | |
| 254 __FUNCTION__, fID, other->fID, tIndexStart - 1, | |
| 255 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX, | |
| 256 xyAtT(tIndexStart).fY); | |
| 257 #endif | |
| 258 SkPoint copy = fTs[tIndexStart].fPt; // add t pair may move the poi
nt array | |
| 259 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false, c
opy); | |
| 260 } | |
| 261 if (nextT < 1 && fTs[tIndex].fWindValue) { | |
| 262 #if DEBUG_CONCIDENT | |
| 263 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", | |
| 264 __FUNCTION__, fID, other->fID, tIndex, | |
| 265 fTs[tIndex].fT, xyAtT(tIndex).fX, | |
| 266 xyAtT(tIndex).fY); | |
| 267 #endif | |
| 268 SkPoint copy = fTs[tIndex].fPt; // add t pair may move the point ar
ray | |
| 269 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, c
opy); | |
| 270 } | |
| 271 } else { | |
| 272 SkASSERT(!other->fTs[oIndexStart].fWindValue); | |
| 273 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) { | |
| 274 #if DEBUG_CONCIDENT | |
| 275 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", | |
| 276 __FUNCTION__, fID, other->fID, oIndexStart - 1, | |
| 277 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX, | |
| 278 other->xyAtT(oIndexStart).fY); | |
| 279 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].
fT); | |
| 280 #endif | |
| 281 } | |
| 282 if (oNextT < 1 && other->fTs[oIndex].fWindValue) { | |
| 283 #if DEBUG_CONCIDENT | |
| 284 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", | |
| 285 __FUNCTION__, fID, other->fID, oIndex, | |
| 286 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX, | |
| 287 other->xyAtT(oIndex).fY); | |
| 288 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].
fT); | |
| 289 #endif | |
| 290 } | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, | |
| 295 SkOpSegment* other) { | |
| 296 // walk this to startPt | |
| 297 // walk other to startPt | |
| 298 // if either is > 0, add a pointer to the other, copying adjacent winding | |
| 299 int tIndex = -1; | |
| 300 int oIndex = -1; | |
| 301 do { | |
| 302 ++tIndex; | |
| 303 } while (startPt != fTs[tIndex].fPt); | |
| 304 int ttIndex = tIndex; | |
| 305 bool checkOtherTMatch = false; | |
| 306 do { | |
| 307 const SkOpSpan& span = fTs[ttIndex]; | |
| 308 if (startPt != span.fPt) { | |
| 309 break; | |
| 310 } | |
| 311 if (span.fOther == other && span.fPt == startPt) { | |
| 312 checkOtherTMatch = true; | |
| 313 break; | |
| 314 } | |
| 315 } while (++ttIndex < count()); | |
| 316 do { | |
| 317 ++oIndex; | |
| 318 } while (startPt != other->fTs[oIndex].fPt); | |
| 319 bool skipAdd = false; | |
| 320 if (checkOtherTMatch) { | |
| 321 int ooIndex = oIndex; | |
| 322 do { | |
| 323 const SkOpSpan& oSpan = other->fTs[ooIndex]; | |
| 324 if (startPt != oSpan.fPt) { | |
| 325 break; | |
| 326 } | |
| 327 if (oSpan.fT == fTs[ttIndex].fOtherT) { | |
| 328 skipAdd = true; | |
| 329 break; | |
| 330 } | |
| 331 } while (++ooIndex < other->count()); | |
| 332 } | |
| 333 if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) { | |
| 334 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt); | |
| 335 } | |
| 336 SkPoint nextPt = startPt; | |
| 337 do { | |
| 338 const SkPoint* workPt; | |
| 339 do { | |
| 340 workPt = &fTs[++tIndex].fPt; | |
| 341 } while (nextPt == *workPt); | |
| 342 const SkPoint* oWorkPt; | |
| 343 do { | |
| 344 oWorkPt = &other->fTs[++oIndex].fPt; | |
| 345 } while (nextPt == *oWorkPt); | |
| 346 nextPt = *workPt; | |
| 347 double tStart = fTs[tIndex].fT; | |
| 348 double oStart = other->fTs[oIndex].fT; | |
| 349 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) { | |
| 350 break; | |
| 351 } | |
| 352 if (*workPt == *oWorkPt) { | |
| 353 addTPair(tStart, other, oStart, false, nextPt); | |
| 354 } | |
| 355 } while (endPt != nextPt); | |
| 356 } | |
| 357 | |
| 358 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) { | |
| 359 init(pts, SkPath::kCubic_Verb, operand, evenOdd); | |
| 360 fBounds.setCubicBounds(pts); | |
| 361 } | |
| 362 | |
| 363 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
) const { | |
| 364 SkPoint edge[4]; | 205 SkPoint edge[4]; |
| 365 const SkPoint* ePtr; | 206 const SkPoint* ePtr; |
| 366 int lastT = fTs.count() - 1; | 207 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
) { |
| 367 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0
)) { | |
| 368 ePtr = fPts; | 208 ePtr = fPts; |
| 369 } else { | 209 } else { |
| 370 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) | 210 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) |
| 371 subDivide(start, end, edge); | 211 subDivide(start, end, edge); |
| 372 ePtr = edge; | 212 ePtr = edge; |
| 373 } | 213 } |
| 374 if (active) { | 214 if (active) { |
| 375 bool reverse = ePtr == fPts && start != 0; | 215 bool reverse = ePtr == fPts && start != &fHead; |
| 376 if (reverse) { | 216 if (reverse) { |
| 377 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); | 217 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); |
| 378 switch (fVerb) { | 218 switch (fVerb) { |
| 379 case SkPath::kLine_Verb: | 219 case SkPath::kLine_Verb: |
| 380 path->deferredLine(ePtr[0]); | 220 path->deferredLine(ePtr[0]); |
| 381 break; | 221 break; |
| 382 case SkPath::kQuad_Verb: | 222 case SkPath::kQuad_Verb: |
| 383 path->quadTo(ePtr[1], ePtr[0]); | 223 path->quadTo(ePtr[1], ePtr[0]); |
| 384 break; | 224 break; |
| 385 case SkPath::kCubic_Verb: | 225 case SkPath::kCubic_Verb: |
| 386 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]); | 226 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]); |
| 387 break; | 227 break; |
| 388 default: | 228 default: |
| 389 SkASSERT(0); | 229 SkASSERT(0); |
| 390 } | 230 } |
| 391 // return ePtr[0]; | |
| 392 } else { | 231 } else { |
| 393 path->deferredMoveLine(ePtr[0]); | 232 path->deferredMoveLine(ePtr[0]); |
| 394 switch (fVerb) { | 233 switch (fVerb) { |
| 395 case SkPath::kLine_Verb: | 234 case SkPath::kLine_Verb: |
| 396 path->deferredLine(ePtr[1]); | 235 path->deferredLine(ePtr[1]); |
| 397 break; | 236 break; |
| 398 case SkPath::kQuad_Verb: | 237 case SkPath::kQuad_Verb: |
| 399 path->quadTo(ePtr[1], ePtr[2]); | 238 path->quadTo(ePtr[1], ePtr[2]); |
| 400 break; | 239 break; |
| 401 case SkPath::kCubic_Verb: | 240 case SkPath::kCubic_Verb: |
| 402 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); | 241 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); |
| 403 break; | 242 break; |
| 404 default: | 243 default: |
| 405 SkASSERT(0); | 244 SkASSERT(0); |
| 406 } | 245 } |
| 407 } | 246 } |
| 408 } | 247 } |
| 409 // return ePtr[SkPathOpsVerbToPoints(fVerb)]; | 248 } |
| 410 } | 249 |
| 411 | 250 SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* alloc
ator) { |
| 412 void SkOpSegment::addEndSpan(int endIndex) { | 251 SkOpSpanBase* existing = NULL; |
| 413 SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny | 252 SkOpSpanBase* test = &fHead; |
| 414 // && approximately_greater_than_one(span(endIndex).fT) | 253 double testT; |
| 415 )); | |
| 416 int spanCount = fTs.count(); | |
| 417 int startIndex = endIndex - 1; | |
| 418 while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) { | |
| 419 --startIndex; | |
| 420 SkASSERT(startIndex > 0); | |
| 421 --endIndex; | |
| 422 } | |
| 423 SkOpAngle& angle = fAngles.push_back(); | |
| 424 angle.set(this, spanCount - 1, startIndex); | |
| 425 #if DEBUG_ANGLE | |
| 426 debugCheckPointsEqualish(endIndex, spanCount); | |
| 427 #endif | |
| 428 setFromAngle(endIndex, &angle); | |
| 429 } | |
| 430 | |
| 431 void SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) { | |
| 432 int spanCount = fTs.count(); | |
| 433 do { | 254 do { |
| 434 fTs[endIndex].fFromAngle = angle; | 255 if ((testT = test->ptT()->fT) >= t) { |
| 435 } while (++endIndex < spanCount); | 256 if (testT == t) { |
| 436 } | 257 existing = test; |
| 437 | 258 } |
| 438 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) { | 259 break; |
| 439 init(pts, SkPath::kLine_Verb, operand, evenOdd); | 260 } |
| 440 fBounds.set(pts, 2); | 261 } while ((test = test->upCast()->next())); |
| 441 } | 262 SkOpPtT* result; |
| 442 | 263 if (existing && existing->contains(opp)) { |
| 443 // add 2 to edge or out of range values to get T extremes | 264 result = existing->ptT(); |
| 444 void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) { | 265 } else { |
| 445 SkOpSpan& span = fTs[index]; | 266 result = this->addT(t, SkOpSegment::kNoAlias, allocator); |
| 446 if (precisely_zero(otherT)) { | 267 } |
| 447 otherT = 0; | 268 SkASSERT(result); |
| 448 } else if (precisely_equal(otherT, 1)) { | 269 return result; |
| 449 otherT = 1; | 270 } |
| 450 } | 271 |
| 451 span.fOtherT = otherT; | 272 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle*
* anglePtr, |
| 452 span.fOtherIndex = otherIndex; | 273 SkChunkAlloc* allocator) { |
| 453 } | 274 SkOpSpan* startSpan = fTail.prev(); |
| 454 | 275 SkASSERT(startSpan); |
| 455 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) { | 276 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 456 init(pts, SkPath::kQuad_Verb, operand, evenOdd); | 277 *anglePtr = angle; |
| 457 fBounds.setQuadBounds(pts); | 278 angle->set(&fTail, startSpan); |
| 458 } | 279 fTail.setFromAngle(angle); |
| 459 | 280 SkOpSegment* other = NULL; // these initializations silence a release build
warning |
| 460 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle*
* anglePtr) { | 281 SkOpSpan* oStartSpan = NULL; |
| 461 int spanIndex = count() - 1; | 282 SkOpSpanBase* oEndSpan = NULL; |
| 462 int startIndex = nextExactSpan(spanIndex, -1); | 283 SkOpPtT* ptT = fTail.ptT(), * startPtT = ptT; |
| 463 SkASSERT(startIndex >= 0); | 284 while ((ptT = ptT->next()) != startPtT) { |
| 464 SkOpAngle& angle = fAngles.push_back(); | 285 other = ptT->segment(); |
| 465 *anglePtr = ∠ | 286 oStartSpan = ptT->span()->upCastable(); |
| 466 angle.set(this, spanIndex, startIndex); | 287 if (oStartSpan && oStartSpan->windValue()) { |
| 467 setFromAngle(spanIndex, &angle); | 288 oEndSpan = oStartSpan->next(); |
| 468 SkOpSegment* other; | 289 break; |
| 469 int oStartIndex, oEndIndex; | 290 } |
| 470 do { | 291 oEndSpan = ptT->span(); |
| 471 const SkOpSpan& span = fTs[spanIndex]; | 292 oStartSpan = oEndSpan->prev(); |
| 472 SkASSERT(span.fT > 0); | 293 if (oStartSpan && oStartSpan->windValue()) { |
| 473 other = span.fOther; | 294 break; |
| 474 oStartIndex = span.fOtherIndex; | 295 } |
| 475 oEndIndex = other->nextExactSpan(oStartIndex, 1); | 296 } |
| 476 if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) { | 297 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 477 break; | 298 oAngle->set(oStartSpan, oEndSpan); |
| 478 } | 299 oStartSpan->setToAngle(oAngle); |
| 479 oEndIndex = oStartIndex; | |
| 480 oStartIndex = other->nextExactSpan(oEndIndex, -1); | |
| 481 --spanIndex; | |
| 482 } while (oStartIndex < 0 || !other->span(oStartIndex).fWindSum); | |
| 483 SkOpAngle& oAngle = other->fAngles.push_back(); | |
| 484 oAngle.set(other, oStartIndex, oEndIndex); | |
| 485 other->setToAngle(oEndIndex, &oAngle); | |
| 486 *otherPtr = other; | 300 *otherPtr = other; |
| 487 return &oAngle; | 301 return oAngle; |
| 488 } | 302 } |
| 489 | 303 |
| 490 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle**
anglePtr) { | 304 SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) { |
| 491 int endIndex = nextExactSpan(0, 1); | |
| 492 SkASSERT(endIndex > 0); | |
| 493 SkOpAngle& angle = fAngles.push_back(); | |
| 494 *anglePtr = ∠ | |
| 495 angle.set(this, 0, endIndex); | |
| 496 setToAngle(endIndex, &angle); | |
| 497 int spanIndex = 0; | |
| 498 SkOpSegment* other; | |
| 499 int oStartIndex, oEndIndex; | |
| 500 do { | |
| 501 const SkOpSpan& span = fTs[spanIndex]; | |
| 502 SkASSERT(span.fT < 1); | |
| 503 other = span.fOther; | |
| 504 oEndIndex = span.fOtherIndex; | |
| 505 oStartIndex = other->nextExactSpan(oEndIndex, -1); | |
| 506 if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) { | |
| 507 break; | |
| 508 } | |
| 509 oStartIndex = oEndIndex; | |
| 510 oEndIndex = other->nextExactSpan(oStartIndex, 1); | |
| 511 ++spanIndex; | |
| 512 } while (oEndIndex < 0 || !other->span(oStartIndex).fWindValue); | |
| 513 SkOpAngle& oAngle = other->fAngles.push_back(); | |
| 514 oAngle.set(other, oEndIndex, oStartIndex); | |
| 515 other->setFromAngle(oEndIndex, &oAngle); | |
| 516 *otherPtr = other; | |
| 517 return &oAngle; | |
| 518 } | |
| 519 | |
| 520 SkOpAngle* SkOpSegment::addSingletonAngles(int step) { | |
| 521 SkOpSegment* other; | 305 SkOpSegment* other; |
| 522 SkOpAngle* angle, * otherAngle; | 306 SkOpAngle* angle, * otherAngle; |
| 523 if (step > 0) { | 307 if (step > 0) { |
| 524 otherAngle = addSingletonAngleUp(&other, &angle); | 308 otherAngle = addSingletonAngleUp(&other, &angle, allocator); |
| 525 } else { | 309 } else { |
| 526 otherAngle = addSingletonAngleDown(&other, &angle); | 310 otherAngle = addSingletonAngleDown(&other, &angle, allocator); |
| 527 } | 311 } |
| 528 angle->insert(otherAngle); | 312 angle->insert(otherAngle); |
| 529 return angle; | 313 return angle; |
| 530 } | 314 } |
| 531 | 315 |
| 532 void SkOpSegment::addStartSpan(int endIndex) { | 316 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle**
anglePtr, |
| 533 int index = 0; | 317 SkChunkAlloc* allocator) { |
| 534 SkOpAngle& angle = fAngles.push_back(); | 318 SkOpSpanBase* endSpan = fHead.next(); |
| 535 angle.set(this, index, endIndex); | 319 SkASSERT(endSpan); |
| 536 #if DEBUG_ANGLE | 320 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 537 debugCheckPointsEqualish(index, endIndex); | 321 *anglePtr = angle; |
| 322 angle->set(&fHead, endSpan); |
| 323 fHead.setToAngle(angle); |
| 324 SkOpSegment* other = NULL; // these initializations silence a release build
warning |
| 325 SkOpSpan* oStartSpan = NULL; |
| 326 SkOpSpanBase* oEndSpan = NULL; |
| 327 SkOpPtT* ptT = fHead.ptT(), * startPtT = ptT; |
| 328 while ((ptT = ptT->next()) != startPtT) { |
| 329 other = ptT->segment(); |
| 330 oEndSpan = ptT->span(); |
| 331 oStartSpan = oEndSpan->prev(); |
| 332 if (oStartSpan && oStartSpan->windValue()) { |
| 333 break; |
| 334 } |
| 335 oStartSpan = oEndSpan->upCastable(); |
| 336 if (oStartSpan && oStartSpan->windValue()) { |
| 337 oEndSpan = oStartSpan->next(); |
| 338 break; |
| 339 } |
| 340 } |
| 341 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 342 oAngle->set(oEndSpan, oStartSpan); |
| 343 oEndSpan->setFromAngle(oAngle); |
| 344 *otherPtr = other; |
| 345 return oAngle; |
| 346 } |
| 347 |
| 348 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca
tor) { |
| 349 debugValidate(); |
| 350 SkPoint pt = this->ptAtT(t); |
| 351 SkOpSpanBase* span = &fHead; |
| 352 do { |
| 353 SkOpPtT* result = span->ptT(); |
| 354 if (t == result->fT) { |
| 355 return result; |
| 356 } |
| 357 if (this->match(result, this, t, pt)) { |
| 358 // see if any existing alias matches segment, pt, and t |
| 359 SkOpPtT* loop = result->next(); |
| 360 bool duplicatePt = false; |
| 361 while (loop != result) { |
| 362 bool ptMatch = loop->fPt == pt; |
| 363 if (loop->segment() == this && loop->fT == t && ptMatch) { |
| 364 return result; |
| 365 } |
| 366 duplicatePt |= ptMatch; |
| 367 loop = loop->next(); |
| 368 } |
| 369 if (kNoAlias == allowAlias) { |
| 370 return result; |
| 371 } |
| 372 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator); |
| 373 alias->init(result->span(), t, pt, duplicatePt); |
| 374 result->insert(alias); |
| 375 result->span()->unaligned(); |
| 376 this->debugValidate(); |
| 377 #if DEBUG_ADD_T |
| 378 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, |
| 379 alias->segment()->debugID(), alias->span()->debugID()); |
| 538 #endif | 380 #endif |
| 539 setToAngle(endIndex, &angle); | 381 return alias; |
| 540 } | 382 } |
| 541 | 383 if (t < result->fT) { |
| 542 void SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) { | 384 SkOpSpan* prev = result->span()->prev(); |
| 543 int index = 0; | 385 SkOpSpan* span = insert(prev, allocator); |
| 386 span->init(this, prev, t, pt); |
| 387 this->debugValidate(); |
| 388 #if DEBUG_ADD_T |
| 389 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, |
| 390 span->segment()->debugID(), span->debugID()); |
| 391 #endif |
| 392 return span->ptT(); |
| 393 } |
| 394 SkASSERT(span != &fTail); |
| 395 } while ((span = span->upCast()->next())); |
| 396 SkASSERT(0); |
| 397 return NULL; |
| 398 } |
| 399 |
| 400 // choose a solitary t and pt value; remove aliases; align the opposite ends |
| 401 void SkOpSegment::align() { |
| 402 debugValidate(); |
| 403 SkOpSpanBase* span = &fHead; |
| 404 if (!span->aligned()) { |
| 405 span->alignEnd(0, fPts[0]); |
| 406 } |
| 407 while ((span = span->upCast()->next())) { |
| 408 if (span == &fTail) { |
| 409 break; |
| 410 } |
| 411 span->align(); |
| 412 } |
| 413 if (!span->aligned()) { |
| 414 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
| 415 } |
| 416 debugValidate(); |
| 417 } |
| 418 |
| 419 bool SkOpSegment::BetweenTs(const SkOpSpanBase* lesser, double testT, |
| 420 const SkOpSpanBase* greater) { |
| 421 if (lesser->t() > greater->t()) { |
| 422 SkTSwap<const SkOpSpanBase*>(lesser, greater); |
| 423 } |
| 424 return approximately_between(lesser->t(), testT, greater->t()); |
| 425 } |
| 426 |
| 427 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) { |
| 428 bool activePrior = !fHead.isCanceled(); |
| 429 if (activePrior && !fHead.simple()) { |
| 430 addStartSpan(allocator); |
| 431 } |
| 432 SkOpSpan* prior = &fHead; |
| 433 SkOpSpanBase* spanBase = fHead.next(); |
| 434 while (spanBase != &fTail) { |
| 435 if (activePrior) { |
| 436 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato
r); |
| 437 priorAngle->set(spanBase, prior); |
| 438 spanBase->setFromAngle(priorAngle); |
| 439 } |
| 440 SkOpSpan* span = spanBase->upCast(); |
| 441 bool active = !span->isCanceled(); |
| 442 SkOpSpanBase* next = span->next(); |
| 443 if (active) { |
| 444 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator); |
| 445 angle->set(span, next); |
| 446 span->setToAngle(angle); |
| 447 } |
| 448 activePrior = active; |
| 449 prior = span; |
| 450 spanBase = next; |
| 451 } |
| 452 if (activePrior && !fTail.simple()) { |
| 453 addEndSpan(allocator); |
| 454 } |
| 455 } |
| 456 |
| 457 void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* al
locator) { |
| 458 SkOpSpanBase* base = &fHead; |
| 459 SkOpSpan* span; |
| 544 do { | 460 do { |
| 545 fTs[index].fToAngle = angle; | 461 SkOpAngle* angle = base->fromAngle(); |
| 546 } while (++index < endIndex); | 462 if (angle && angle->fCheckCoincidence) { |
| 547 } | 463 angle->checkNearCoincidence(); |
| 548 | 464 } |
| 549 // Defer all coincident edge processing until | 465 if (base->final()) { |
| 550 // after normal intersections have been computed | 466 break; |
| 551 | 467 } |
| 552 // no need to be tricky; insert in normal T order | 468 span = base->upCast(); |
| 553 // resolve overlapping ts when considering coincidence later | 469 angle = span->toAngle(); |
| 554 | 470 if (angle && angle->fCheckCoincidence) { |
| 555 // add non-coincident intersection. Resulting edges are sorted in T. | 471 angle->checkNearCoincidence(); |
| 556 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { | 472 } |
| 557 SkASSERT(this != other || fVerb == SkPath::kCubic_Verb); | 473 } while ((base = span->next())); |
| 558 #if 0 // this needs an even rougher association to be useful | 474 } |
| 559 SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt)); | 475 |
| 560 #endif | 476 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
| 561 const SkPoint& firstPt = fPts[0]; | 477 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
bool* swap) const { |
| 562 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)]; | 478 SkASSERT(fVerb != SkPath::kLine_Verb); |
| 563 SkASSERT(newT == 0 || !precisely_zero(newT)); | 479 SkPoint edge[4]; |
| 564 SkASSERT(newT == 1 || !precisely_equal(newT, 1)); | 480 if (fVerb == SkPath::kCubic_Verb) { |
| 565 // FIXME: in the pathological case where there is a ton of intercepts, | 481 double startT = start->t(); |
| 566 // binary search? | 482 double endT = end->t(); |
| 567 int insertedAt = -1; | 483 bool flip = startT > endT; |
| 568 int tCount = fTs.count(); | 484 SkDCubic cubic; |
| 569 for (int index = 0; index < tCount; ++index) { | 485 cubic.set(fPts); |
| 570 // OPTIMIZATION: if there are three or more identical Ts, then | 486 double inflectionTs[2]; |
| 571 // the fourth and following could be further insertion-sorted so | 487 int inflections = cubic.findInflections(inflectionTs); |
| 572 // that all the edges are clockwise or counterclockwise. | 488 for (int index = 0; index < inflections; ++index) { |
| 573 // This could later limit segment tests to the two adjacent | 489 double inflectionT = inflectionTs[index]; |
| 574 // neighbors, although it doesn't help with determining which | 490 if (between(startT, inflectionT, endT)) { |
| 575 // circular direction to go in. | 491 if (flip) { |
| 576 const SkOpSpan& span = fTs[index]; | 492 if (inflectionT != endT) { |
| 577 if (newT < span.fT) { | 493 startT = inflectionT; |
| 578 insertedAt = index; | 494 } |
| 579 break; | |
| 580 } | |
| 581 if (newT == span.fT) { | |
| 582 if (pt == span.fPt) { | |
| 583 insertedAt = index; | |
| 584 break; | |
| 585 } | |
| 586 if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1
)) { | |
| 587 insertedAt = index; | |
| 588 break; | |
| 589 } | |
| 590 } | |
| 591 } | |
| 592 SkOpSpan* span; | |
| 593 if (insertedAt >= 0) { | |
| 594 span = fTs.insert(insertedAt); | |
| 595 } else { | |
| 596 insertedAt = tCount; | |
| 597 span = fTs.append(); | |
| 598 } | |
| 599 span->fT = newT; | |
| 600 span->fOtherT = -1; | |
| 601 span->fOther = other; | |
| 602 span->fPt = pt; | |
| 603 #if 0 | |
| 604 // cubics, for instance, may not be exact enough to satisfy this check (e.g.
, cubicOp69d) | |
| 605 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) | |
| 606 && approximately_equal(xyAtT(newT).fY, pt.fY)); | |
| 607 #endif | |
| 608 span->fFromAngle = NULL; | |
| 609 span->fToAngle = NULL; | |
| 610 span->fWindSum = SK_MinS32; | |
| 611 span->fOppSum = SK_MinS32; | |
| 612 span->fWindValue = 1; | |
| 613 span->fOppValue = 0; | |
| 614 span->fChased = false; | |
| 615 span->fCoincident = false; | |
| 616 span->fLoop = false; | |
| 617 span->fNear = false; | |
| 618 span->fMultiple = false; | |
| 619 span->fSmall = false; | |
| 620 span->fTiny = false; | |
| 621 if ((span->fDone = newT == 1)) { | |
| 622 ++fDoneSpans; | |
| 623 } | |
| 624 setSpanFlags(pt, newT, span); | |
| 625 return insertedAt; | |
| 626 } | |
| 627 | |
| 628 void SkOpSegment::setSpanFlags(const SkPoint& pt, double newT, SkOpSpan* span) { | |
| 629 int less = -1; | |
| 630 // FIXME: note that this relies on spans being a continguous array | |
| 631 // find range of spans with nearly the same point as this one | |
| 632 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the mom
ent | |
| 633 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt,
pt)) { | |
| 634 if (fVerb == SkPath::kCubic_Verb) { | |
| 635 double tInterval = newT - span[less].fT; | |
| 636 double tMid = newT - tInterval / 2; | |
| 637 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); | |
| 638 if (!midPt.approximatelyEqual(xyAtT(span))) { | |
| 639 break; | |
| 640 } | |
| 641 } | |
| 642 --less; | |
| 643 } | |
| 644 int more = 1; | |
| 645 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the mom
ent | |
| 646 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt
)) { | |
| 647 if (fVerb == SkPath::kCubic_Verb) { | |
| 648 double tEndInterval = span[more].fT - newT; | |
| 649 double tMid = newT - tEndInterval / 2; | |
| 650 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); | |
| 651 if (!midEndPt.approximatelyEqual(xyAtT(span))) { | |
| 652 break; | |
| 653 } | |
| 654 } | |
| 655 ++more; | |
| 656 } | |
| 657 ++less; | |
| 658 --more; | |
| 659 while (more - 1 > less && span[more].fPt == span[more - 1].fPt | |
| 660 && span[more].fT == span[more - 1].fT) { | |
| 661 --more; | |
| 662 } | |
| 663 if (less == more) { | |
| 664 return; | |
| 665 } | |
| 666 if (precisely_negative(span[more].fT - span[less].fT)) { | |
| 667 return; | |
| 668 } | |
| 669 // if the total range of t values is big enough, mark all tiny | |
| 670 bool tiny = span[less].fPt == span[more].fPt; | |
| 671 int index = less; | |
| 672 do { | |
| 673 fSmall = span[index].fSmall = true; | |
| 674 fTiny |= span[index].fTiny = tiny; | |
| 675 if (!span[index].fDone) { | |
| 676 span[index].fDone = true; | |
| 677 ++fDoneSpans; | |
| 678 } | |
| 679 } while (++index < more); | |
| 680 return; | |
| 681 } | |
| 682 | |
| 683 void SkOpSegment::resetSpanFlags() { | |
| 684 fSmall = fTiny = false; | |
| 685 fDoneSpans = 0; | |
| 686 int start = 0; | |
| 687 int last = this->count() - 1; | |
| 688 do { | |
| 689 SkOpSpan* startSpan = &this->fTs[start]; | |
| 690 double startT = startSpan->fT; | |
| 691 startSpan->fSmall = startSpan->fTiny = false; // sets range initial | |
| 692 bool terminus = startT == 1; | |
| 693 if ((startSpan->fDone = !startSpan->fWindValue | terminus)) { | |
| 694 ++fDoneSpans; | |
| 695 } | |
| 696 ++start; // range initial + 1 | |
| 697 if (terminus) { | |
| 698 continue; | |
| 699 } | |
| 700 const SkPoint& pt = startSpan->fPt; | |
| 701 int end = start; // range initial + 1 | |
| 702 while (end <= last) { | |
| 703 const SkOpSpan& endSpan = this->span(end); | |
| 704 if (!AlmostEqualUlps(endSpan.fPt, pt)) { | |
| 705 break; | |
| 706 } | |
| 707 if (fVerb == SkPath::kCubic_Verb) { | |
| 708 double tMid = (startSpan->fT + endSpan.fT) / 2; | |
| 709 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); | |
| 710 if (!midEndPt.approximatelyEqual(xyAtT(startSpan))) { | |
| 711 break; | |
| 712 } | |
| 713 } | |
| 714 ++end; | |
| 715 } | |
| 716 if (start == end) { // end == range final + 1 | |
| 717 continue; | |
| 718 } | |
| 719 while (--end >= start) { // end == range final | |
| 720 const SkOpSpan& endSpan = this->span(end); | |
| 721 const SkOpSpan& priorSpan = this->span(end - 1); | |
| 722 if (endSpan.fPt != priorSpan.fPt || endSpan.fT != priorSpan.fT) { | |
| 723 break; // end == range final + 1 | |
| 724 } | |
| 725 } | |
| 726 if (end < start) { // end == range final + 1 | |
| 727 continue; | |
| 728 } | |
| 729 int index = start - 1; // index == range initial | |
| 730 start = end; // start = range final + 1 | |
| 731 const SkOpSpan& nextSpan = this->span(end); | |
| 732 if (precisely_negative(nextSpan.fT - startSpan->fT)) { | |
| 733 while (++index < end) { | |
| 734 startSpan = &this->fTs[index]; | |
| 735 startSpan->fSmall = startSpan->fTiny = false; // sets range ini
tial + 1 | |
| 736 if ((startSpan->fDone = !startSpan->fWindValue)) { | |
| 737 ++fDoneSpans; | |
| 738 } | |
| 739 } | |
| 740 continue; | |
| 741 } | |
| 742 if (!startSpan->fWindValue) { | |
| 743 --fDoneSpans; // added back below | |
| 744 } | |
| 745 bool tiny = nextSpan.fPt == startSpan->fPt; | |
| 746 do { | |
| 747 fSmall = startSpan->fSmall = true; // sets range initial | |
| 748 fTiny |= startSpan->fTiny = tiny; | |
| 749 startSpan->fDone = true; | |
| 750 ++fDoneSpans; | |
| 751 startSpan = &this->fTs[++index]; | |
| 752 } while (index < end); // loop through tiny small range end (last) | |
| 753 } while (start <= last); | |
| 754 } | |
| 755 | |
| 756 // set spans from start to end to decrement by one | |
| 757 // note this walks other backwards | |
| 758 // FIXME: there's probably an edge case that can be constructed where | |
| 759 // two span in one segment are separated by float epsilon on one span but | |
| 760 // not the other, if one segment is very small. For this | |
| 761 // case the counts asserted below may or may not be enough to separate the | |
| 762 // spans. Even if the counts work out, what if the spans aren't correctly | |
| 763 // sorted? It feels better in such a case to match the span's other span | |
| 764 // pointer since both coincident segments must contain the same spans. | |
| 765 // FIXME? It seems that decrementing by one will fail for complex paths that | |
| 766 // have three or more coincident edges. Shouldn't this subtract the difference | |
| 767 // between the winding values? | |
| 768 /* |--> |--> | |
| 769 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>
4 | |
| 770 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0 | |
| 771 ^ ^ <--| <--| | |
| 772 startPt endPt test/oTest first pos test/oTest final po
s | |
| 773 */ | |
| 774 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other) { | |
| 775 bool binary = fOperand != other->fOperand; | |
| 776 int index = 0; | |
| 777 while (startPt != fTs[index].fPt) { | |
| 778 SkASSERT(index < fTs.count()); | |
| 779 ++index; | |
| 780 } | |
| 781 while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) { | |
| 782 --index; | |
| 783 } | |
| 784 bool oFoundEnd = false; | |
| 785 int oIndex = other->fTs.count(); | |
| 786 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match | |
| 787 SkASSERT(oIndex > 0); | |
| 788 } | |
| 789 double oStartT = other->fTs[oIndex].fT; | |
| 790 // look for first point beyond match | |
| 791 while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other
->fTs[oIndex].fT)) { | |
| 792 if (!oIndex) { | |
| 793 return; // tiny spans may move in the wrong direction | |
| 794 } | |
| 795 } | |
| 796 SkOpSpan* test = &fTs[index]; | |
| 797 SkOpSpan* oTest = &other->fTs[oIndex]; | |
| 798 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; | |
| 799 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | |
| 800 bool decrement, track, bigger; | |
| 801 int originalWindValue; | |
| 802 const SkPoint* testPt; | |
| 803 const SkPoint* oTestPt; | |
| 804 do { | |
| 805 SkASSERT(test->fT < 1); | |
| 806 SkASSERT(oTest->fT < 1); | |
| 807 decrement = test->fWindValue && oTest->fWindValue; | |
| 808 track = test->fWindValue || oTest->fWindValue; | |
| 809 bigger = test->fWindValue >= oTest->fWindValue; | |
| 810 testPt = &test->fPt; | |
| 811 double testT = test->fT; | |
| 812 oTestPt = &oTest->fPt; | |
| 813 double oTestT = oTest->fT; | |
| 814 do { | |
| 815 if (decrement) { | |
| 816 if (binary && bigger) { | |
| 817 test->fOppValue--; | |
| 818 } else { | 495 } else { |
| 819 decrementSpan(test); | 496 if (inflectionT != startT) { |
| 820 } | 497 endT = inflectionT; |
| 821 } else if (track) { | |
| 822 TrackOutsidePair(&outsidePts, *testPt, *oTestPt); | |
| 823 } | |
| 824 SkASSERT(index < fTs.count() - 1); | |
| 825 test = &fTs[++index]; | |
| 826 } while (*testPt == test->fPt || precisely_equal(testT, test->fT)); | |
| 827 originalWindValue = oTest->fWindValue; | |
| 828 do { | |
| 829 SkASSERT(oTest->fT < 1); | |
| 830 SkASSERT(originalWindValue == oTest->fWindValue); | |
| 831 if (decrement) { | |
| 832 if (binary && !bigger) { | |
| 833 oTest->fOppValue--; | |
| 834 } else { | |
| 835 other->decrementSpan(oTest); | |
| 836 } | |
| 837 } else if (track) { | |
| 838 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt); | |
| 839 } | |
| 840 if (!oIndex) { | |
| 841 break; | |
| 842 } | |
| 843 oFoundEnd |= endPt == oTest->fPt; | |
| 844 oTest = &other->fTs[--oIndex]; | |
| 845 } while (*oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT)); | |
| 846 } while (endPt != test->fPt && test->fT < 1); | |
| 847 // FIXME: determine if canceled edges need outside ts added | |
| 848 if (!oFoundEnd) { | |
| 849 for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) { | |
| 850 SkOpSpan* oTst2 = &other->fTs[oIdx2]; | |
| 851 if (originalWindValue != oTst2->fWindValue) { | |
| 852 goto skipAdvanceOtherCancel; | |
| 853 } | |
| 854 if (!oTst2->fWindValue) { | |
| 855 goto skipAdvanceOtherCancel; | |
| 856 } | |
| 857 if (endPt == other->fTs[oIdx2].fPt) { | |
| 858 break; | |
| 859 } | |
| 860 } | |
| 861 oFoundEnd = endPt == oTest->fPt; | |
| 862 do { | |
| 863 SkASSERT(originalWindValue == oTest->fWindValue); | |
| 864 if (decrement) { | |
| 865 if (binary && !bigger) { | |
| 866 oTest->fOppValue--; | |
| 867 } else { | |
| 868 other->decrementSpan(oTest); | |
| 869 } | |
| 870 } else if (track) { | |
| 871 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt); | |
| 872 } | |
| 873 if (!oIndex) { | |
| 874 break; | |
| 875 } | |
| 876 oTest = &other->fTs[--oIndex]; | |
| 877 oFoundEnd |= endPt == oTest->fPt; | |
| 878 } while (!oFoundEnd || endPt == oTest->fPt); | |
| 879 } | |
| 880 skipAdvanceOtherCancel: | |
| 881 int outCount = outsidePts.count(); | |
| 882 if (!done() && outCount) { | |
| 883 addCancelOutsides(outsidePts[0], outsidePts[1], other); | |
| 884 if (outCount > 2) { | |
| 885 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1]
, other); | |
| 886 } | |
| 887 } | |
| 888 if (!other->done() && oOutsidePts.count()) { | |
| 889 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); | |
| 890 } | |
| 891 setCoincidentRange(startPt, endPt, other); | |
| 892 other->setCoincidentRange(startPt, endPt, this); | |
| 893 } | |
| 894 | |
| 895 int SkOpSegment::addSelfT(const SkPoint& pt, double newT) { | |
| 896 // if the tail nearly intersects itself but not quite, the caller records th
is separately | |
| 897 int result = addT(this, pt, newT); | |
| 898 SkOpSpan* span = &fTs[result]; | |
| 899 fLoop = span->fLoop = true; | |
| 900 return result; | |
| 901 } | |
| 902 | |
| 903 // find the starting or ending span with an existing loop of angles | |
| 904 // FIXME? replicate for all identical starting/ending spans? | |
| 905 // OPTIMIZE? remove the spans pointing to windValue==0 here or earlier? | |
| 906 // FIXME? assert that only one other span has a valid windValue or oppValue | |
| 907 void SkOpSegment::addSimpleAngle(int index) { | |
| 908 SkOpSpan* span = &fTs[index]; | |
| 909 int idx; | |
| 910 int start, end; | |
| 911 if (span->fT == 0) { | |
| 912 idx = 0; | |
| 913 span = &fTs[0]; | |
| 914 do { | |
| 915 if (span->fToAngle) { | |
| 916 SkASSERT(span->fToAngle->loopCount() == 2); | |
| 917 SkASSERT(!span->fFromAngle); | |
| 918 span->fFromAngle = span->fToAngle->next(); | |
| 919 return; | |
| 920 } | |
| 921 span = &fTs[++idx]; | |
| 922 } while (span->fT == 0); | |
| 923 SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0); | |
| 924 addStartSpan(idx); | |
| 925 start = 0; | |
| 926 end = idx; | |
| 927 } else { | |
| 928 idx = count() - 1; | |
| 929 span = &fTs[idx]; | |
| 930 do { | |
| 931 if (span->fFromAngle) { | |
| 932 SkASSERT(span->fFromAngle->loopCount() == 2); | |
| 933 SkASSERT(!span->fToAngle); | |
| 934 span->fToAngle = span->fFromAngle->next(); | |
| 935 return; | |
| 936 } | |
| 937 span = &fTs[--idx]; | |
| 938 } while (span->fT == 1); | |
| 939 SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1); | |
| 940 addEndSpan(++idx); | |
| 941 start = idx; | |
| 942 end = count(); | |
| 943 } | |
| 944 SkOpSegment* other; | |
| 945 SkOpSpan* oSpan; | |
| 946 index = start; | |
| 947 do { | |
| 948 span = &fTs[index]; | |
| 949 other = span->fOther; | |
| 950 int oFrom = span->fOtherIndex; | |
| 951 oSpan = &other->fTs[oFrom]; | |
| 952 if (oSpan->fT < 1 && oSpan->fWindValue) { | |
| 953 break; | |
| 954 } | |
| 955 if (oSpan->fT == 0) { | |
| 956 continue; | |
| 957 } | |
| 958 oFrom = other->nextExactSpan(oFrom, -1); | |
| 959 SkOpSpan* oFromSpan = &other->fTs[oFrom]; | |
| 960 SkASSERT(oFromSpan->fT < 1); | |
| 961 if (oFromSpan->fWindValue) { | |
| 962 break; | |
| 963 } | |
| 964 } while (++index < end); | |
| 965 SkOpAngle* angle, * oAngle; | |
| 966 if (span->fT == 0) { | |
| 967 SkASSERT(span->fOtherIndex - 1 >= 0); | |
| 968 SkASSERT(span->fOtherT == 1); | |
| 969 SkDEBUGCODE(int oPriorIndex = other->nextExactSpan(span->fOtherIndex, -1
)); | |
| 970 SkDEBUGCODE(const SkOpSpan& oPrior = other->span(oPriorIndex)); | |
| 971 SkASSERT(!oPrior.fTiny && oPrior.fT < 1); | |
| 972 other->addEndSpan(span->fOtherIndex); | |
| 973 angle = span->fToAngle; | |
| 974 oAngle = oSpan->fFromAngle; | |
| 975 } else { | |
| 976 SkASSERT(span->fOtherIndex + 1 < other->count()); | |
| 977 SkASSERT(span->fOtherT == 0); | |
| 978 SkASSERT(!oSpan->fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0 | |
| 979 || (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL | |
| 980 && other->fTs[span->fOtherIndex + 1].fToAngle == NULL))); | |
| 981 int oIndex = 1; | |
| 982 do { | |
| 983 const SkOpSpan& osSpan = other->span(oIndex); | |
| 984 if (osSpan.fFromAngle || osSpan.fT > 0) { | |
| 985 break; | |
| 986 } | |
| 987 ++oIndex; | |
| 988 SkASSERT(oIndex < other->count()); | |
| 989 } while (true); | |
| 990 other->addStartSpan(oIndex); | |
| 991 angle = span->fFromAngle; | |
| 992 oAngle = oSpan->fToAngle; | |
| 993 } | |
| 994 angle->insert(oAngle); | |
| 995 } | |
| 996 | |
| 997 void SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) { | |
| 998 debugValidate(); | |
| 999 int count = this->count(); | |
| 1000 for (int index = 0; index < count; ++index) { | |
| 1001 SkOpSpan& span = fTs[index]; | |
| 1002 if (!span.fMultiple) { | |
| 1003 continue; | |
| 1004 } | |
| 1005 int end = nextExactSpan(index, 1); | |
| 1006 SkASSERT(end > index + 1); | |
| 1007 const SkPoint& thisPt = span.fPt; | |
| 1008 while (index < end - 1) { | |
| 1009 SkOpSegment* other1 = span.fOther; | |
| 1010 int oCnt = other1->count(); | |
| 1011 for (int idx2 = index + 1; idx2 < end; ++idx2) { | |
| 1012 SkOpSpan& span2 = fTs[idx2]; | |
| 1013 SkOpSegment* other2 = span2.fOther; | |
| 1014 for (int oIdx = 0; oIdx < oCnt; ++oIdx) { | |
| 1015 SkOpSpan& oSpan = other1->fTs[oIdx]; | |
| 1016 if (oSpan.fOther != other2) { | |
| 1017 continue; | |
| 1018 } | |
| 1019 if (oSpan.fPt == thisPt) { | |
| 1020 goto skipExactMatches; | |
| 1021 } | 498 } |
| 1022 } | 499 } |
| 1023 for (int oIdx = 0; oIdx < oCnt; ++oIdx) { | 500 } |
| 1024 SkOpSpan& oSpan = other1->fTs[oIdx]; | 501 } |
| 1025 if (oSpan.fOther != other2) { | 502 SkDCubic part = cubic.subDivide(startT, endT); |
| 1026 continue; | 503 for (int index = 0; index < 4; ++index) { |
| 1027 } | 504 edge[index] = part[index].asSkPoint(); |
| 1028 if (SkDPoint::RoughlyEqual(oSpan.fPt, thisPt)) { | 505 } |
| 1029 SkOpSpan& oSpan2 = other2->fTs[oSpan.fOtherIndex]; | 506 } else { |
| 1030 if (zero_or_one(span.fOtherT) || zero_or_one(oSpan.fT) | 507 subDivide(start, end, edge); |
| 1031 || zero_or_one(span2.fOtherT) || zero_or_one(oSp
an2.fT)) { | 508 } |
| 1032 return; | 509 bool sumSet = false; |
| 1033 } | 510 int points = SkPathOpsVerbToPoints(fVerb); |
| 1034 if (!way_roughly_equal(span.fOtherT, oSpan.fT) | 511 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; |
| 1035 || !way_roughly_equal(span2.fOtherT, oSpan2.fT) | 512 if (!sumSet) { |
| 1036 || !way_roughly_equal(span2.fOtherT, oSpan.fOthe
rT) | 513 for (int idx = 0; idx < points; ++idx){ |
| 1037 || !way_roughly_equal(span.fOtherT, oSpan2.fOthe
rT)) { | 514 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[
idx].fY); |
| 1038 return; | 515 } |
| 1039 } | 516 } |
| 1040 alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT, | 517 if (fVerb == SkPath::kCubic_Verb) { |
| 1041 other2, &oSpan, alignedArray); | 518 SkDCubic cubic; |
| 1042 alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT, | 519 cubic.set(edge); |
| 1043 other1, &oSpan2, alignedArray); | 520 *swap = sum > 0 && !cubic.monotonicInY(); |
| 1044 break; | 521 } else { |
| 1045 } | 522 SkDQuad quad; |
| 1046 } | 523 quad.set(edge); |
| 1047 skipExactMatches: | 524 *swap = sum > 0 && !quad.monotonicInY(); |
| 1048 ; | 525 } |
| 1049 } | 526 return sum <= 0; |
| 1050 ++index; | 527 } |
| 1051 } | 528 |
| 1052 } | 529 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
| 1053 debugValidate(); | 530 SkOpAngle::IncludeType includeType) { |
| 1054 } | 531 const SkOpSegment* baseSegment = baseAngle->segment(); |
| 1055 | 532 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
| 1056 void SkOpSegment::alignRange(int lower, int upper, | 533 int sumSuWinding; |
| 1057 const SkOpSegment* other, int oLower, int oUpper) { | 534 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 1058 for (int oIndex = oLower; oIndex <= oUpper; ++oIndex) { | |
| 1059 const SkOpSpan& oSpan = other->span(oIndex); | |
| 1060 const SkOpSegment* oOther = oSpan.fOther; | |
| 1061 if (oOther == this) { | |
| 1062 continue; | |
| 1063 } | |
| 1064 SkOpSpan* matchSpan; | |
| 1065 int matchIndex; | |
| 1066 const SkOpSpan* refSpan; | |
| 1067 for (int iIndex = lower; iIndex <= upper; ++iIndex) { | |
| 1068 const SkOpSpan& iSpan = this->span(iIndex); | |
| 1069 const SkOpSegment* iOther = iSpan.fOther; | |
| 1070 if (iOther == other) { | |
| 1071 continue; | |
| 1072 } | |
| 1073 if (iOther == oOther) { | |
| 1074 goto nextI; | |
| 1075 } | |
| 1076 } | |
| 1077 { | |
| 1078 // oSpan does not have a match in this | |
| 1079 int iCount = this->count(); | |
| 1080 const SkOpSpan* iMatch = NULL; | |
| 1081 double iMatchTDiff; | |
| 1082 matchIndex = -1; | |
| 1083 for (int iIndex = 0; iIndex < iCount; ++iIndex) { | |
| 1084 const SkOpSpan& iSpan = this->span(iIndex); | |
| 1085 const SkOpSegment* iOther = iSpan.fOther; | |
| 1086 if (iOther != oOther) { | |
| 1087 continue; | |
| 1088 } | |
| 1089 double testTDiff = fabs(iSpan.fOtherT - oSpan.fOtherT); | |
| 1090 if (!iMatch || testTDiff < iMatchTDiff) { | |
| 1091 matchIndex = iIndex; | |
| 1092 iMatch = &iSpan; | |
| 1093 iMatchTDiff = testTDiff; | |
| 1094 } | |
| 1095 } | |
| 1096 if (matchIndex < 0) { | |
| 1097 continue; // the entry is missing, & will be picked up later (F
IXME: fix it here?) | |
| 1098 } | |
| 1099 matchSpan = &this->fTs[matchIndex]; | |
| 1100 refSpan = &this->span(lower); | |
| 1101 if (!SkDPoint::ApproximatelyEqual(matchSpan->fPt, refSpan->fPt)) { | |
| 1102 goto nextI; | |
| 1103 } | |
| 1104 if (matchIndex != lower - 1 && matchIndex != upper + 1) { | |
| 1105 // the consecutive spans need to be rearranged to get the missin
g one close | |
| 1106 continue; // FIXME: more work to do | |
| 1107 } | |
| 1108 } | |
| 1109 { | |
| 1110 this->fixOtherTIndex(); | |
| 1111 SkScalar newT; | |
| 1112 if (matchSpan->fT != 0 && matchSpan->fT != 1) { | |
| 1113 newT = matchSpan->fT = refSpan->fT; | |
| 1114 matchSpan->fOther->fTs[matchSpan->fOtherIndex].fOtherT = refSpan
->fT; | |
| 1115 } else { // leave span at the start or end there and adjust the nei
ghbors | |
| 1116 newT = matchSpan->fT; | |
| 1117 for (int iIndex = lower; iIndex <= upper; ++iIndex) { | |
| 1118 matchSpan = &this->fTs[iIndex]; | |
| 1119 matchSpan->fT = newT; | |
| 1120 matchSpan->fOther->fTs[matchSpan->fOtherIndex].fOtherT = new
T; | |
| 1121 } | |
| 1122 } | |
| 1123 this->resetSpanFlags(); // fix up small / tiny / done | |
| 1124 // align ts of other ranges with adjacent spans that match the align
ed points | |
| 1125 lower = SkTMin(lower, matchIndex); | |
| 1126 while (lower > 0) { | |
| 1127 const SkOpSpan& span = this->span(lower - 1); | |
| 1128 if (span.fT != newT) { | |
| 1129 break; | |
| 1130 } | |
| 1131 --lower; | |
| 1132 } | |
| 1133 upper = SkTMax(upper, matchIndex); | |
| 1134 int last = this->count() - 1; | |
| 1135 while (upper < last) { | |
| 1136 const SkOpSpan& span = this->span(upper + 1); | |
| 1137 if (span.fT != newT) { | |
| 1138 break; | |
| 1139 } | |
| 1140 ++upper; | |
| 1141 } | |
| 1142 for (int iIndex = lower; iIndex <= upper; ++iIndex) { | |
| 1143 const SkOpSpan& span = this->span(iIndex); | |
| 1144 SkOpSegment* aOther = span.fOther; | |
| 1145 int aLower = span.fOtherIndex; | |
| 1146 SkScalar aT = span.fOtherT; | |
| 1147 bool aResetFlags = false; | |
| 1148 while (aLower > 0) { | |
| 1149 SkOpSpan* aSpan = &aOther->fTs[aLower - 1]; | |
| 1150 for (int iIndex = lower; iIndex <= upper; ++iIndex) { | |
| 1151 if (aSpan->fPt == this->fTs[iIndex].fPt) { | |
| 1152 goto matchFound; | |
| 1153 } | |
| 1154 } | |
| 1155 break; | |
| 1156 matchFound: | |
| 1157 --aLower; | |
| 1158 } | |
| 1159 int aUpper = span.fOtherIndex; | |
| 1160 int aLast = aOther->count() - 1; | |
| 1161 while (aUpper < aLast) { | |
| 1162 SkOpSpan* aSpan = &aOther->fTs[aUpper + 1]; | |
| 1163 for (int iIndex = lower; iIndex <= upper; ++iIndex) { | |
| 1164 if (aSpan->fPt == this->fTs[iIndex].fPt) { | |
| 1165 goto matchFound2; | |
| 1166 } | |
| 1167 } | |
| 1168 break; | |
| 1169 matchFound2: | |
| 1170 ++aUpper; | |
| 1171 } | |
| 1172 if (aOther->fTs[aLower].fT == 0) { | |
| 1173 aT = 0; | |
| 1174 } else if (aOther->fTs[aUpper].fT == 1) { | |
| 1175 aT = 1; | |
| 1176 } | |
| 1177 bool aFixed = false; | |
| 1178 for (int aIndex = aLower; aIndex <= aUpper; ++aIndex) { | |
| 1179 SkOpSpan* aSpan = &aOther->fTs[aIndex]; | |
| 1180 if (aSpan->fT == aT) { | |
| 1181 continue; | |
| 1182 } | |
| 1183 SkASSERT(way_roughly_equal(aSpan->fT, aT)); | |
| 1184 if (!aFixed) { | |
| 1185 aOther->fixOtherTIndex(); | |
| 1186 aFixed = true; | |
| 1187 } | |
| 1188 aSpan->fT = aT; | |
| 1189 aSpan->fOther->fTs[aSpan->fOtherIndex].fOtherT = aT; | |
| 1190 aResetFlags = true; | |
| 1191 } | |
| 1192 if (aResetFlags) { | |
| 1193 aOther->resetSpanFlags(); | |
| 1194 } | |
| 1195 } | |
| 1196 } | |
| 1197 nextI: ; | |
| 1198 } | |
| 1199 } | |
| 1200 | |
| 1201 void SkOpSegment::alignSpan(const SkPoint& newPt, double newT, const SkOpSegment
* other, | |
| 1202 double otherT, const SkOpSegment* other2, SkOpSpan* oSpan, | |
| 1203 SkTDArray<AlignedSpan>* alignedArray) { | |
| 1204 AlignedSpan* aligned = alignedArray->append(); | |
| 1205 aligned->fOldPt = oSpan->fPt; | |
| 1206 aligned->fPt = newPt; | |
| 1207 aligned->fOldT = oSpan->fT; | |
| 1208 aligned->fT = newT; | |
| 1209 aligned->fSegment = this; // OPTIMIZE: may be unused, can remove | |
| 1210 aligned->fOther1 = other; | |
| 1211 aligned->fOther2 = other2; | |
| 1212 SkASSERT(SkDPoint::RoughlyEqual(oSpan->fPt, newPt)); | |
| 1213 oSpan->fPt = newPt; | |
| 1214 // SkASSERT(way_roughly_equal(oSpan->fT, newT)); | |
| 1215 oSpan->fT = newT; | |
| 1216 // SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT)); | |
| 1217 oSpan->fOtherT = otherT; | |
| 1218 } | |
| 1219 | |
| 1220 bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) { | |
| 1221 bool aligned = false; | |
| 1222 SkOpSpan* span = &fTs[index]; | |
| 1223 SkOpSegment* other = span->fOther; | |
| 1224 int oIndex = span->fOtherIndex; | |
| 1225 SkOpSpan* oSpan = &other->fTs[oIndex]; | |
| 1226 if (span->fT != thisT) { | |
| 1227 span->fT = thisT; | |
| 1228 oSpan->fOtherT = thisT; | |
| 1229 aligned = true; | |
| 1230 } | |
| 1231 if (span->fPt != thisPt) { | |
| 1232 span->fPt = thisPt; | |
| 1233 oSpan->fPt = thisPt; | |
| 1234 aligned = true; | |
| 1235 } | |
| 1236 double oT = oSpan->fT; | |
| 1237 if (oT == 0) { | |
| 1238 return aligned; | |
| 1239 } | |
| 1240 int oStart = other->nextSpan(oIndex, -1) + 1; | |
| 1241 oSpan = &other->fTs[oStart]; | |
| 1242 int otherIndex = oStart; | |
| 1243 if (oT == 1) { | |
| 1244 if (aligned) { | |
| 1245 while (oSpan->fPt == thisPt && oSpan->fT != 1) { | |
| 1246 oSpan->fTiny = true; | |
| 1247 ++oSpan; | |
| 1248 } | |
| 1249 } | |
| 1250 return aligned; | |
| 1251 } | |
| 1252 oT = oSpan->fT; | |
| 1253 int oEnd = other->nextSpan(oIndex, 1); | |
| 1254 bool oAligned = false; | |
| 1255 if (oSpan->fPt != thisPt) { | |
| 1256 oAligned |= other->alignSpan(oStart, oT, thisPt); | |
| 1257 } | |
| 1258 while (++otherIndex < oEnd) { | |
| 1259 SkOpSpan* oNextSpan = &other->fTs[otherIndex]; | |
| 1260 if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) { | |
| 1261 oAligned |= other->alignSpan(otherIndex, oT, thisPt); | |
| 1262 } | |
| 1263 } | |
| 1264 if (oAligned) { | |
| 1265 other->alignSpanState(oStart, oEnd); | |
| 1266 } | |
| 1267 return aligned; | |
| 1268 } | |
| 1269 | |
| 1270 void SkOpSegment::alignSpanState(int start, int end) { | |
| 1271 SkOpSpan* lastSpan = &fTs[--end]; | |
| 1272 bool allSmall = lastSpan->fSmall; | |
| 1273 bool allTiny = lastSpan->fTiny; | |
| 1274 bool allDone = lastSpan->fDone; | |
| 1275 SkDEBUGCODE(int winding = lastSpan->fWindValue); | |
| 1276 SkDEBUGCODE(int oppWinding = lastSpan->fOppValue); | |
| 1277 int index = start; | |
| 1278 while (index < end) { | |
| 1279 SkOpSpan* span = &fTs[index]; | |
| 1280 span->fSmall = allSmall; | |
| 1281 span->fTiny = allTiny; | |
| 1282 if (span->fDone != allDone) { | |
| 1283 span->fDone = allDone; | |
| 1284 fDoneSpans += allDone ? 1 : -1; | |
| 1285 } | |
| 1286 SkASSERT(span->fWindValue == winding); | |
| 1287 SkASSERT(span->fOppValue == oppWinding); | |
| 1288 ++index; | |
| 1289 } | |
| 1290 } | |
| 1291 | |
| 1292 void SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* oth
er) { | |
| 1293 bool binary = fOperand != other->fOperand; | |
| 1294 int index = 0; | |
| 1295 int last = this->count(); | |
| 1296 do { | |
| 1297 SkOpSpan& span = this->fTs[--last]; | |
| 1298 if (span.fT != 1 && !span.fSmall) { | |
| 1299 break; | |
| 1300 } | |
| 1301 span.fCoincident = true; | |
| 1302 } while (true); | |
| 1303 int oIndex = other->count(); | |
| 1304 do { | |
| 1305 SkOpSpan& oSpan = other->fTs[--oIndex]; | |
| 1306 if (oSpan.fT != 1 && !oSpan.fSmall) { | |
| 1307 break; | |
| 1308 } | |
| 1309 oSpan.fCoincident = true; | |
| 1310 } while (true); | |
| 1311 do { | |
| 1312 SkOpSpan* test = &this->fTs[index]; | |
| 1313 int baseWind = test->fWindValue; | |
| 1314 int baseOpp = test->fOppValue; | |
| 1315 int endIndex = index; | |
| 1316 while (++endIndex <= last) { | |
| 1317 SkOpSpan* endSpan = &this->fTs[endIndex]; | |
| 1318 SkASSERT(endSpan->fT < 1); | |
| 1319 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp
) { | |
| 1320 break; | |
| 1321 } | |
| 1322 endSpan->fCoincident = true; | |
| 1323 } | |
| 1324 SkOpSpan* oTest = &other->fTs[oIndex]; | |
| 1325 int oBaseWind = oTest->fWindValue; | |
| 1326 int oBaseOpp = oTest->fOppValue; | |
| 1327 int oStartIndex = oIndex; | |
| 1328 while (--oStartIndex >= 0) { | |
| 1329 SkOpSpan* oStartSpan = &other->fTs[oStartIndex]; | |
| 1330 if (oStartSpan->fWindValue != oBaseWind || oStartSpan->fOppValue !=
oBaseOpp) { | |
| 1331 break; | |
| 1332 } | |
| 1333 oStartSpan->fCoincident = true; | |
| 1334 } | |
| 1335 bool decrement = baseWind && oBaseWind; | |
| 1336 bool bigger = baseWind >= oBaseWind; | |
| 1337 do { | |
| 1338 SkASSERT(test->fT < 1); | |
| 1339 if (decrement) { | |
| 1340 if (binary && bigger) { | |
| 1341 test->fOppValue--; | |
| 1342 } else { | |
| 1343 decrementSpan(test); | |
| 1344 } | |
| 1345 } | |
| 1346 test->fCoincident = true; | |
| 1347 test = &fTs[++index]; | |
| 1348 } while (index < endIndex); | |
| 1349 do { | |
| 1350 SkASSERT(oTest->fT < 1); | |
| 1351 if (decrement) { | |
| 1352 if (binary && !bigger) { | |
| 1353 oTest->fOppValue--; | |
| 1354 } else { | |
| 1355 other->decrementSpan(oTest); | |
| 1356 } | |
| 1357 } | |
| 1358 oTest->fCoincident = true; | |
| 1359 oTest = &other->fTs[--oIndex]; | |
| 1360 } while (oIndex > oStartIndex); | |
| 1361 } while (index <= last && oIndex >= 0); | |
| 1362 SkASSERT(index > last); | |
| 1363 SkASSERT(oIndex < 0); | |
| 1364 } | |
| 1365 | |
| 1366 void SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment*
other) { | |
| 1367 bool binary = fOperand != other->fOperand; | |
| 1368 int index = 0; | |
| 1369 int last = this->count(); | |
| 1370 do { | |
| 1371 SkOpSpan& span = this->fTs[--last]; | |
| 1372 if (span.fT != 1 && !span.fSmall) { | |
| 1373 break; | |
| 1374 } | |
| 1375 span.fCoincident = true; | |
| 1376 } while (true); | |
| 1377 int oIndex = 0; | |
| 1378 int oLast = other->count(); | |
| 1379 do { | |
| 1380 SkOpSpan& oSpan = other->fTs[--oLast]; | |
| 1381 if (oSpan.fT != 1 && !oSpan.fSmall) { | |
| 1382 break; | |
| 1383 } | |
| 1384 oSpan.fCoincident = true; | |
| 1385 } while (true); | |
| 1386 do { | |
| 1387 SkOpSpan* test = &this->fTs[index]; | |
| 1388 int baseWind = test->fWindValue; | |
| 1389 int baseOpp = test->fOppValue; | |
| 1390 int endIndex = index; | |
| 1391 SkOpSpan* endSpan; | |
| 1392 while (++endIndex <= last) { | |
| 1393 endSpan = &this->fTs[endIndex]; | |
| 1394 SkASSERT(endSpan->fT < 1); | |
| 1395 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp
) { | |
| 1396 break; | |
| 1397 } | |
| 1398 endSpan->fCoincident = true; | |
| 1399 } | |
| 1400 SkOpSpan* oTest = &other->fTs[oIndex]; | |
| 1401 int oBaseWind = oTest->fWindValue; | |
| 1402 int oBaseOpp = oTest->fOppValue; | |
| 1403 int oEndIndex = oIndex; | |
| 1404 SkOpSpan* oEndSpan; | |
| 1405 while (++oEndIndex <= oLast) { | |
| 1406 oEndSpan = &this->fTs[oEndIndex]; | |
| 1407 SkASSERT(oEndSpan->fT < 1); | |
| 1408 if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBas
eOpp) { | |
| 1409 break; | |
| 1410 } | |
| 1411 oEndSpan->fCoincident = true; | |
| 1412 } | |
| 1413 // consolidate the winding count even if done | |
| 1414 if ((test->fWindValue || test->fOppValue) && (oTest->fWindValue || oTest
->fOppValue)) { | |
| 1415 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { | |
| 1416 bumpCoincidentBlind(binary, index, endIndex); | |
| 1417 other->bumpCoincidentOBlind(oIndex, oEndIndex); | |
| 1418 } else { | |
| 1419 other->bumpCoincidentBlind(binary, oIndex, oEndIndex); | |
| 1420 bumpCoincidentOBlind(index, endIndex); | |
| 1421 } | |
| 1422 } | |
| 1423 index = endIndex; | |
| 1424 oIndex = oEndIndex; | |
| 1425 } while (index <= last && oIndex <= oLast); | |
| 1426 SkASSERT(index > last); | |
| 1427 SkASSERT(oIndex > oLast); | |
| 1428 } | |
| 1429 | |
| 1430 void SkOpSegment::bumpCoincidentBlind(bool binary, int index, int endIndex) { | |
| 1431 const SkOpSpan& oTest = fTs[index]; | |
| 1432 int oWindValue = oTest.fWindValue; | |
| 1433 int oOppValue = oTest.fOppValue; | |
| 1434 if (binary) { | 535 if (binary) { |
| 1435 SkTSwap<int>(oWindValue, oOppValue); | 536 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); |
| 1436 } | 537 if (baseSegment->operand()) { |
| 1437 do { | 538 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 1438 (void) bumpSpan(&fTs[index], oWindValue, oOppValue); | 539 } |
| 1439 } while (++index < endIndex); | 540 } |
| 1440 } | 541 SkOpSegment* nextSegment = nextAngle->segment(); |
| 1441 | 542 int maxWinding, sumWinding; |
| 1442 bool SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* in
dexPtr, | 543 SkOpSpanBase* last; |
| 1443 SkTArray<SkPoint, true>* outsideTs) { | |
| 1444 int index = *indexPtr; | |
| 1445 int oWindValue = oTest.fWindValue; | |
| 1446 int oOppValue = oTest.fOppValue; | |
| 1447 if (binary) { | 544 if (binary) { |
| 1448 SkTSwap<int>(oWindValue, oOppValue); | 545 int oppMaxWinding, oppSumWinding; |
| 1449 } | 546 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, |
| 1450 SkOpSpan* const test = &fTs[index]; | 547 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); |
| 1451 SkOpSpan* end = test; | 548 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, |
| 1452 const SkPoint& oStartPt = oTest.fPt; | 549 nextAngle); |
| 1453 do { | 550 } else { |
| 1454 if (end->fDone && !end->fTiny && !end->fSmall) { // extremely large pat
hs trigger this | 551 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, |
| 1455 return false; | 552 &maxWinding, &sumWinding); |
| 1456 } | 553 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); |
| 1457 if (bumpSpan(end, oWindValue, oOppValue)) { | 554 } |
| 1458 TrackOutside(outsideTs, oStartPt); | 555 nextAngle->setLastMarked(last); |
| 1459 } | 556 } |
| 1460 end = &fTs[++index]; | 557 |
| 1461 } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && en
d->fT < 1); | 558 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne
xtAngle, |
| 1462 *indexPtr = index; | 559 SkOpAngle::IncludeType includeType) { |
| 1463 return true; | 560 const SkOpSegment* baseSegment = baseAngle->segment(); |
| 1464 } | 561 int sumMiWinding = baseSegment->updateWinding(baseAngle); |
| 1465 | 562 int sumSuWinding; |
| 1466 void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) { | 563 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 1467 do { | 564 if (binary) { |
| 1468 zeroSpan(&fTs[index]); | 565 sumSuWinding = baseSegment->updateOppWinding(baseAngle); |
| 1469 } while (++index < endIndex); | 566 if (baseSegment->operand()) { |
| 1470 } | 567 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 1471 | 568 } |
| 1472 // because of the order in which coincidences are resolved, this and other | 569 } |
| 1473 // may not have the same intermediate points. Compute the corresponding | 570 SkOpSegment* nextSegment = nextAngle->segment(); |
| 1474 // intermediate T values (using this as the master, other as the follower) | 571 int maxWinding, sumWinding; |
| 1475 // and walk other conditionally -- hoping that it catches up in the end | 572 SkOpSpanBase* last; |
| 1476 bool SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, | 573 if (binary) { |
| 1477 SkTArray<SkPoint, true>* oOutsidePts, const SkPoint& oEndPt) { | 574 int oppMaxWinding, oppSumWinding; |
| 1478 int oIndex = *oIndexPtr; | 575 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, |
| 1479 SkOpSpan* const oTest = &fTs[oIndex]; | 576 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); |
| 1480 SkOpSpan* oEnd = oTest; | 577 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, |
| 1481 const SkPoint& oStartPt = oTest->fPt; | 578 nextAngle); |
| 1482 double oStartT = oTest->fT; | 579 } else { |
| 1483 #if 0 // FIXME : figure out what disabling this breaks | 580 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, |
| 1484 const SkPoint& startPt = test.fPt; | 581 &maxWinding, &sumWinding); |
| 1485 // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find
proper condition | 582 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); |
| 1486 if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { | 583 } |
| 1487 TrackOutside(oOutsidePts, startPt); | 584 nextAngle->setLastMarked(last); |
| 1488 } | |
| 1489 #endif | |
| 1490 bool foundEnd = false; | |
| 1491 while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { | |
| 1492 foundEnd |= oEndPt == oEnd->fPt; | |
| 1493 zeroSpan(oEnd); | |
| 1494 oEnd = &fTs[++oIndex]; | |
| 1495 } | |
| 1496 *oIndexPtr = oIndex; | |
| 1497 return foundEnd; | |
| 1498 } | |
| 1499 | |
| 1500 // FIXME: need to test this case: | |
| 1501 // contourA has two segments that are coincident | |
| 1502 // contourB has two segments that are coincident in the same place | |
| 1503 // each ends up with +2/0 pairs for winding count | |
| 1504 // since logic below doesn't transfer count (only increments/decrements) can thi
s be | |
| 1505 // resolved to +4/0 ? | |
| 1506 | |
| 1507 // set spans from start to end to increment the greater by one and decrement | |
| 1508 // the lesser | |
| 1509 bool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
ouble endT, | |
| 1510 SkOpSegment* other) { | |
| 1511 bool binary = fOperand != other->fOperand; | |
| 1512 int index = 0; | |
| 1513 while (startPt != fTs[index].fPt) { | |
| 1514 SkASSERT(index < fTs.count()); | |
| 1515 ++index; | |
| 1516 } | |
| 1517 double startT = fTs[index].fT; | |
| 1518 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) { | |
| 1519 --index; | |
| 1520 } | |
| 1521 int oIndex = 0; | |
| 1522 while (startPt != other->fTs[oIndex].fPt) { | |
| 1523 SkASSERT(oIndex < other->fTs.count()); | |
| 1524 ++oIndex; | |
| 1525 } | |
| 1526 double oStartT = other->fTs[oIndex].fT; | |
| 1527 while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) { | |
| 1528 --oIndex; | |
| 1529 } | |
| 1530 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; | |
| 1531 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | |
| 1532 SkOpSpan* test = &fTs[index]; | |
| 1533 const SkPoint* testPt = &test->fPt; | |
| 1534 double testT = test->fT; | |
| 1535 SkOpSpan* oTest = &other->fTs[oIndex]; | |
| 1536 const SkPoint* oTestPt = &oTest->fPt; | |
| 1537 // paths with extreme data will fail this test and eject out of pathops alto
gether later on | |
| 1538 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | |
| 1539 do { | |
| 1540 SkASSERT(test->fT < 1); | |
| 1541 if (oTest->fT == 1) { | |
| 1542 // paths with extreme data may be so mismatched that we fail here | |
| 1543 return false; | |
| 1544 } | |
| 1545 | |
| 1546 // consolidate the winding count even if done | |
| 1547 bool foundEnd = false; | |
| 1548 if ((test->fWindValue == 0 && test->fOppValue == 0) | |
| 1549 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { | |
| 1550 SkDEBUGCODE(int firstWind = test->fWindValue); | |
| 1551 SkDEBUGCODE(int firstOpp = test->fOppValue); | |
| 1552 do { | |
| 1553 SkASSERT(firstWind == fTs[index].fWindValue); | |
| 1554 SkASSERT(firstOpp == fTs[index].fOppValue); | |
| 1555 ++index; | |
| 1556 SkASSERT(index < fTs.count()); | |
| 1557 } while (*testPt == fTs[index].fPt); | |
| 1558 SkDEBUGCODE(firstWind = oTest->fWindValue); | |
| 1559 SkDEBUGCODE(firstOpp = oTest->fOppValue); | |
| 1560 do { | |
| 1561 SkASSERT(firstWind == other->fTs[oIndex].fWindValue); | |
| 1562 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue); | |
| 1563 ++oIndex; | |
| 1564 SkASSERT(oIndex < other->fTs.count()); | |
| 1565 } while (*oTestPt == other->fTs[oIndex].fPt); | |
| 1566 } else { | |
| 1567 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { | |
| 1568 if (!bumpCoincidentThis(*oTest, binary, &index, &outsidePts)) { | |
| 1569 return false; | |
| 1570 } | |
| 1571 foundEnd = other->bumpCoincidentOther(*test, &oIndex, &oOutsideP
ts, endPt); | |
| 1572 } else { | |
| 1573 if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOutside
Pts)) { | |
| 1574 return false; | |
| 1575 } | |
| 1576 foundEnd = bumpCoincidentOther(*oTest, &index, &outsidePts, endP
t); | |
| 1577 } | |
| 1578 } | |
| 1579 test = &fTs[index]; | |
| 1580 testPt = &test->fPt; | |
| 1581 testT = test->fT; | |
| 1582 oTest = &other->fTs[oIndex]; | |
| 1583 oTestPt = &oTest->fPt; | |
| 1584 if (endPt == *testPt || precisely_equal(endT, testT)) { | |
| 1585 break; | |
| 1586 } | |
| 1587 if (0 && foundEnd) { // FIXME: this is likely needed but wait until a t
est case triggers it | |
| 1588 break; | |
| 1589 } | |
| 1590 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | |
| 1591 } while (endPt != *oTestPt); | |
| 1592 // in rare cases, one may have ended before the other | |
| 1593 if (endPt != *testPt && !precisely_equal(endT, testT)) { | |
| 1594 int lastWind = test[-1].fWindValue; | |
| 1595 int lastOpp = test[-1].fOppValue; | |
| 1596 bool zero = lastWind == 0 && lastOpp == 0; | |
| 1597 do { | |
| 1598 if (test->fWindValue || test->fOppValue) { | |
| 1599 test->fWindValue = lastWind; | |
| 1600 test->fOppValue = lastOpp; | |
| 1601 if (zero) { | |
| 1602 SkASSERT(!test->fDone); | |
| 1603 test->fDone = true; | |
| 1604 ++fDoneSpans; | |
| 1605 } | |
| 1606 } | |
| 1607 test = &fTs[++index]; | |
| 1608 testPt = &test->fPt; | |
| 1609 } while (endPt != *testPt); | |
| 1610 } | |
| 1611 if (endPt != *oTestPt) { | |
| 1612 // look ahead to see if zeroing more spans will allows us to catch up | |
| 1613 int oPeekIndex = oIndex; | |
| 1614 bool success = true; | |
| 1615 SkOpSpan* oPeek; | |
| 1616 int oCount = other->count(); | |
| 1617 do { | |
| 1618 oPeek = &other->fTs[oPeekIndex]; | |
| 1619 if (++oPeekIndex == oCount) { | |
| 1620 success = false; | |
| 1621 break; | |
| 1622 } | |
| 1623 } while (endPt != oPeek->fPt); | |
| 1624 if (success) { | |
| 1625 // make sure the matching point completes the coincidence span | |
| 1626 success = false; | |
| 1627 do { | |
| 1628 if (oPeek->fOther == this) { | |
| 1629 success = true; | |
| 1630 break; | |
| 1631 } | |
| 1632 if (++oPeekIndex == oCount) { | |
| 1633 break; | |
| 1634 } | |
| 1635 oPeek = &other->fTs[oPeekIndex]; | |
| 1636 } while (endPt == oPeek->fPt); | |
| 1637 } | |
| 1638 if (success) { | |
| 1639 do { | |
| 1640 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { | |
| 1641 if (other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts,
endPt)) { | |
| 1642 break; | |
| 1643 } | |
| 1644 } else { | |
| 1645 if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOut
sidePts)) { | |
| 1646 return false; | |
| 1647 } | |
| 1648 } | |
| 1649 oTest = &other->fTs[oIndex]; | |
| 1650 oTestPt = &oTest->fPt; | |
| 1651 } while (endPt != *oTestPt); | |
| 1652 } | |
| 1653 } | |
| 1654 int outCount = outsidePts.count(); | |
| 1655 if (!done() && outCount) { | |
| 1656 addCoinOutsides(outsidePts[0], endPt, other); | |
| 1657 } | |
| 1658 if (!other->done() && oOutsidePts.count()) { | |
| 1659 other->addCoinOutsides(oOutsidePts[0], endPt, this); | |
| 1660 } | |
| 1661 setCoincidentRange(startPt, endPt, other); | |
| 1662 other->setCoincidentRange(startPt, endPt, this); | |
| 1663 return true; | |
| 1664 } | |
| 1665 | |
| 1666 // FIXME: this doesn't prevent the same span from being added twice | |
| 1667 // fix in caller, SkASSERT here? | |
| 1668 // FIXME: this may erroneously reject adds for cubic loops | |
| 1669 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other
T, bool borrowWind, | |
| 1670 const SkPoint& pt, const SkPoint& pt2) { | |
| 1671 int tCount = fTs.count(); | |
| 1672 for (int tIndex = 0; tIndex < tCount; ++tIndex) { | |
| 1673 const SkOpSpan& span = fTs[tIndex]; | |
| 1674 if (!approximately_negative(span.fT - t)) { | |
| 1675 break; | |
| 1676 } | |
| 1677 if (span.fOther == other) { | |
| 1678 bool tsMatch = approximately_equal(span.fT, t); | |
| 1679 bool otherTsMatch = approximately_equal(span.fOtherT, otherT); | |
| 1680 // FIXME: add cubic loop detecting logic here | |
| 1681 // if fLoop bit is set on span, that could be enough if addOtherT co
pies the bit | |
| 1682 // or if a new bit is added ala fOtherLoop | |
| 1683 if (tsMatch || otherTsMatch) { | |
| 1684 #if DEBUG_ADD_T_PAIR | |
| 1685 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", | |
| 1686 __FUNCTION__, fID, t, other->fID, otherT); | |
| 1687 #endif | |
| 1688 return NULL; | |
| 1689 } | |
| 1690 } | |
| 1691 } | |
| 1692 int oCount = other->count(); | |
| 1693 for (int oIndex = 0; oIndex < oCount; ++oIndex) { | |
| 1694 const SkOpSpan& oSpan = other->span(oIndex); | |
| 1695 if (!approximately_negative(oSpan.fT - otherT)) { | |
| 1696 break; | |
| 1697 } | |
| 1698 if (oSpan.fOther == this) { | |
| 1699 bool otherTsMatch = approximately_equal(oSpan.fT, otherT); | |
| 1700 bool tsMatch = approximately_equal(oSpan.fOtherT, t); | |
| 1701 if (otherTsMatch || tsMatch) { | |
| 1702 #if DEBUG_ADD_T_PAIR | |
| 1703 SkDebugf("%s addTPair other duplicate this=%d %1.9g other=%d %1.
9g\n", | |
| 1704 __FUNCTION__, fID, t, other->fID, otherT); | |
| 1705 #endif | |
| 1706 return NULL; | |
| 1707 } | |
| 1708 } | |
| 1709 } | |
| 1710 #if DEBUG_ADD_T_PAIR | |
| 1711 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", | |
| 1712 __FUNCTION__, fID, t, other->fID, otherT); | |
| 1713 #endif | |
| 1714 SkASSERT(other != this); | |
| 1715 int insertedAt = addT(other, pt, t); | |
| 1716 int otherInsertedAt = other->addT(this, pt2, otherT); | |
| 1717 this->addOtherT(insertedAt, otherT, otherInsertedAt); | |
| 1718 other->addOtherT(otherInsertedAt, t, insertedAt); | |
| 1719 this->matchWindingValue(insertedAt, t, borrowWind); | |
| 1720 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); | |
| 1721 SkOpSpan& span = this->fTs[insertedAt]; | |
| 1722 if (pt != pt2) { | |
| 1723 span.fNear = true; | |
| 1724 SkOpSpan& oSpan = other->fTs[otherInsertedAt]; | |
| 1725 oSpan.fNear = true; | |
| 1726 } | |
| 1727 // if the newly inserted spans match a neighbor on one but not the other, ma
ke them agree | |
| 1728 int lower = this->nextExactSpan(insertedAt, -1) + 1; | |
| 1729 int upper = this->nextExactSpan(insertedAt, 1) - 1; | |
| 1730 if (upper < 0) { | |
| 1731 upper = this->count() - 1; | |
| 1732 } | |
| 1733 int oLower = other->nextExactSpan(otherInsertedAt, -1) + 1; | |
| 1734 int oUpper = other->nextExactSpan(otherInsertedAt, 1) - 1; | |
| 1735 if (oUpper < 0) { | |
| 1736 oUpper = other->count() - 1; | |
| 1737 } | |
| 1738 if (lower == upper && oLower == oUpper) { | |
| 1739 return &span; | |
| 1740 } | |
| 1741 #if DEBUG_CONCIDENT | |
| 1742 SkDebugf("%s id=%d lower=%d upper=%d other=%d oLower=%d oUpper=%d\n", __FUNC
TION__, | |
| 1743 debugID(), lower, upper, other->debugID(), oLower, oUpper); | |
| 1744 #endif | |
| 1745 // find the nearby spans in one range missing in the other | |
| 1746 this->alignRange(lower, upper, other, oLower, oUpper); | |
| 1747 other->alignRange(oLower, oUpper, this, lower, upper); | |
| 1748 return &span; | |
| 1749 } | |
| 1750 | |
| 1751 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other
T, bool borrowWind, | |
| 1752 const SkPoint& pt) { | |
| 1753 return addTPair(t, other, otherT, borrowWind, pt, pt); | |
| 1754 } | |
| 1755 | |
| 1756 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint&
pt2) const { | |
| 1757 const SkPoint midPt = ptAtT(midT); | |
| 1758 SkPathOpsBounds bounds; | |
| 1759 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY); | |
| 1760 bounds.sort(); | |
| 1761 return bounds.almostContains(midPt); | |
| 1762 } | |
| 1763 | |
| 1764 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const { | |
| 1765 if (lesser > greater) { | |
| 1766 SkTSwap<int>(lesser, greater); | |
| 1767 } | |
| 1768 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); | |
| 1769 } | |
| 1770 | |
| 1771 // in extreme cases (like the buffer overflow test) return false to abort | |
| 1772 // for now, if one t value represents two different points, then the values are
too extreme | |
| 1773 // to generate meaningful results | |
| 1774 bool SkOpSegment::calcAngles() { | |
| 1775 int spanCount = fTs.count(); | |
| 1776 if (spanCount <= 2) { | |
| 1777 return spanCount == 2; | |
| 1778 } | |
| 1779 int index = 1; | |
| 1780 const SkOpSpan* firstSpan = &fTs[index]; | |
| 1781 int activePrior = checkSetAngle(0); | |
| 1782 const SkOpSpan* span = &fTs[0]; | |
| 1783 if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther-
>multipleEnds()) { | |
| 1784 index = findStartSpan(0); // curve start intersects | |
| 1785 if (fTs[index].fT == 0) { | |
| 1786 return false; | |
| 1787 } | |
| 1788 SkASSERT(index > 0); | |
| 1789 if (activePrior >= 0) { | |
| 1790 addStartSpan(index); | |
| 1791 } | |
| 1792 } | |
| 1793 bool addEnd; | |
| 1794 int endIndex = spanCount - 1; | |
| 1795 span = &fTs[endIndex - 1]; | |
| 1796 if ((addEnd = span->fT == 1 || span->fTiny)) { // if curve end intersects | |
| 1797 endIndex = findEndSpan(endIndex); | |
| 1798 SkASSERT(endIndex > 0); | |
| 1799 } else { | |
| 1800 addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleSta
rts(); | |
| 1801 } | |
| 1802 SkASSERT(endIndex >= index); | |
| 1803 int prior = 0; | |
| 1804 while (index < endIndex) { | |
| 1805 const SkOpSpan& fromSpan = fTs[index]; // for each intermediate interse
ction | |
| 1806 const SkOpSpan* lastSpan; | |
| 1807 span = &fromSpan; | |
| 1808 int start = index; | |
| 1809 do { | |
| 1810 lastSpan = span; | |
| 1811 span = &fTs[++index]; | |
| 1812 SkASSERT(index < spanCount); | |
| 1813 if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny
) { | |
| 1814 break; | |
| 1815 } | |
| 1816 if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) { | |
| 1817 return false; | |
| 1818 } | |
| 1819 } while (true); | |
| 1820 SkOpAngle* angle = NULL; | |
| 1821 SkOpAngle* priorAngle; | |
| 1822 if (activePrior >= 0) { | |
| 1823 int pActive = firstActive(prior); | |
| 1824 SkASSERT(pActive < start); | |
| 1825 priorAngle = &fAngles.push_back(); | |
| 1826 priorAngle->set(this, start, pActive); | |
| 1827 } | |
| 1828 int active = checkSetAngle(start); | |
| 1829 if (active >= 0) { | |
| 1830 SkASSERT(active < index); | |
| 1831 angle = &fAngles.push_back(); | |
| 1832 angle->set(this, active, index); | |
| 1833 } | |
| 1834 #if DEBUG_ANGLE | |
| 1835 debugCheckPointsEqualish(start, index); | |
| 1836 #endif | |
| 1837 prior = start; | |
| 1838 do { | |
| 1839 const SkOpSpan* startSpan = &fTs[start - 1]; | |
| 1840 if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromA
ngle | |
| 1841 || startSpan->fToAngle) { | |
| 1842 break; | |
| 1843 } | |
| 1844 --start; | |
| 1845 } while (start > 0); | |
| 1846 do { | |
| 1847 if (activePrior >= 0) { | |
| 1848 SkASSERT(fTs[start].fFromAngle == NULL); | |
| 1849 fTs[start].fFromAngle = priorAngle; | |
| 1850 } | |
| 1851 if (active >= 0) { | |
| 1852 SkASSERT(fTs[start].fToAngle == NULL); | |
| 1853 fTs[start].fToAngle = angle; | |
| 1854 } | |
| 1855 } while (++start < index); | |
| 1856 activePrior = active; | |
| 1857 } | |
| 1858 if (addEnd && activePrior >= 0) { | |
| 1859 addEndSpan(endIndex); | |
| 1860 } | |
| 1861 return true; | |
| 1862 } | |
| 1863 | |
| 1864 int SkOpSegment::checkSetAngle(int tIndex) const { | |
| 1865 const SkOpSpan* span = &fTs[tIndex]; | |
| 1866 while (span->fTiny /* || span->fSmall */) { | |
| 1867 span = &fTs[++tIndex]; | |
| 1868 } | |
| 1869 return isCanceled(tIndex) ? -1 : tIndex; | |
| 1870 } | 585 } |
| 1871 | 586 |
| 1872 // at this point, the span is already ordered, or unorderable | 587 // at this point, the span is already ordered, or unorderable |
| 1873 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType
includeType) { | 588 int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end, |
| 589 SkOpAngle::IncludeType includeType) { |
| 1874 SkASSERT(includeType != SkOpAngle::kUnaryXor); | 590 SkASSERT(includeType != SkOpAngle::kUnaryXor); |
| 1875 SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex); | 591 SkOpAngle* firstAngle = this->spanToAngle(end, start); |
| 1876 if (NULL == firstAngle || NULL == firstAngle->next()) { | 592 if (NULL == firstAngle || NULL == firstAngle->next()) { |
| 1877 return SK_NaN32; | 593 return SK_NaN32; |
| 1878 } | 594 } |
| 1879 // if all angles have a computed winding, | 595 // if all angles have a computed winding, |
| 1880 // or if no adjacent angles are orderable, | 596 // or if no adjacent angles are orderable, |
| 1881 // or if adjacent orderable angles have no computed winding, | 597 // or if adjacent orderable angles have no computed winding, |
| 1882 // there's nothing to do | 598 // there's nothing to do |
| 1883 // if two orderable angles are adjacent, and both are next to orderable angl
es, | 599 // if two orderable angles are adjacent, and both are next to orderable angl
es, |
| 1884 // and one has winding computed, transfer to the other | 600 // and one has winding computed, transfer to the other |
| 1885 SkOpAngle* baseAngle = NULL; | 601 SkOpAngle* baseAngle = NULL; |
| 1886 bool tryReverse = false; | 602 bool tryReverse = false; |
| 1887 // look for counterclockwise transfers | 603 // look for counterclockwise transfers |
| 1888 SkOpAngle* angle = firstAngle->previous(); | 604 SkOpAngle* angle = firstAngle->previous(); |
| 1889 SkOpAngle* next = angle->next(); | 605 SkOpAngle* next = angle->next(); |
| 1890 firstAngle = next; | 606 firstAngle = next; |
| 1891 do { | 607 do { |
| 1892 SkOpAngle* prior = angle; | 608 SkOpAngle* prior = angle; |
| 1893 angle = next; | 609 angle = next; |
| 1894 next = angle->next(); | 610 next = angle->next(); |
| 1895 SkASSERT(prior->next() == angle); | 611 SkASSERT(prior->next() == angle); |
| 1896 SkASSERT(angle->next() == next); | 612 SkASSERT(angle->next() == next); |
| 1897 if (prior->unorderable() || angle->unorderable() || next->unorderable())
{ | 613 if (prior->unorderable() || angle->unorderable() || next->unorderable())
{ |
| 1898 baseAngle = NULL; | 614 baseAngle = NULL; |
| 1899 continue; | 615 continue; |
| 1900 } | 616 } |
| 1901 int testWinding = angle->segment()->windSum(angle); | 617 int testWinding = angle->starter()->windSum(); |
| 1902 if (SK_MinS32 != testWinding) { | 618 if (SK_MinS32 != testWinding) { |
| 1903 baseAngle = angle; | 619 baseAngle = angle; |
| 1904 tryReverse = true; | 620 tryReverse = true; |
| 1905 continue; | 621 continue; |
| 1906 } | 622 } |
| 1907 if (baseAngle) { | 623 if (baseAngle) { |
| 1908 ComputeOneSum(baseAngle, angle, includeType); | 624 ComputeOneSum(baseAngle, angle, includeType); |
| 1909 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle :
NULL; | 625 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL; |
| 1910 } | 626 } |
| 1911 } while (next != firstAngle); | 627 } while (next != firstAngle); |
| 1912 if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) { | 628 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) { |
| 1913 firstAngle = baseAngle; | 629 firstAngle = baseAngle; |
| 1914 tryReverse = true; | 630 tryReverse = true; |
| 1915 } | 631 } |
| 1916 if (tryReverse) { | 632 if (tryReverse) { |
| 1917 baseAngle = NULL; | 633 baseAngle = NULL; |
| 1918 SkOpAngle* prior = firstAngle; | 634 SkOpAngle* prior = firstAngle; |
| 1919 do { | 635 do { |
| 1920 angle = prior; | 636 angle = prior; |
| 1921 prior = angle->previous(); | 637 prior = angle->previous(); |
| 1922 SkASSERT(prior->next() == angle); | 638 SkASSERT(prior->next() == angle); |
| 1923 next = angle->next(); | 639 next = angle->next(); |
| 1924 if (prior->unorderable() || angle->unorderable() || next->unorderabl
e()) { | 640 if (prior->unorderable() || angle->unorderable() || next->unorderabl
e()) { |
| 1925 baseAngle = NULL; | 641 baseAngle = NULL; |
| 1926 continue; | 642 continue; |
| 1927 } | 643 } |
| 1928 int testWinding = angle->segment()->windSum(angle); | 644 int testWinding = angle->starter()->windSum(); |
| 1929 if (SK_MinS32 != testWinding) { | 645 if (SK_MinS32 != testWinding) { |
| 1930 baseAngle = angle; | 646 baseAngle = angle; |
| 1931 continue; | 647 continue; |
| 1932 } | 648 } |
| 1933 if (baseAngle) { | 649 if (baseAngle) { |
| 1934 ComputeOneSumReverse(baseAngle, angle, includeType); | 650 ComputeOneSumReverse(baseAngle, angle, includeType); |
| 1935 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angl
e : NULL; | 651 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : N
ULL; |
| 1936 } | 652 } |
| 1937 } while (prior != firstAngle); | 653 } while (prior != firstAngle); |
| 1938 } | 654 } |
| 1939 int minIndex = SkMin32(startIndex, endIndex); | 655 return start->starter(end)->windSum(); |
| 1940 return windSum(minIndex); | |
| 1941 } | 656 } |
| 1942 | 657 |
| 1943 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, | 658 SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp,
bool current, |
| 1944 SkOpAngle::IncludeType includeType) { | 659 SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical) { |
| 1945 const SkOpSegment* baseSegment = baseAngle->segment(); | |
| 1946 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | |
| 1947 int sumSuWinding; | |
| 1948 bool binary = includeType >= SkOpAngle::kBinarySingle; | |
| 1949 if (binary) { | |
| 1950 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); | |
| 1951 if (baseSegment->operand()) { | |
| 1952 SkTSwap<int>(sumMiWinding, sumSuWinding); | |
| 1953 } | |
| 1954 } | |
| 1955 SkOpSegment* nextSegment = nextAngle->segment(); | |
| 1956 int maxWinding, sumWinding; | |
| 1957 SkOpSpan* last; | |
| 1958 if (binary) { | |
| 1959 int oppMaxWinding, oppSumWinding; | |
| 1960 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, | |
| 1961 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); | |
| 1962 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, | |
| 1963 nextAngle); | |
| 1964 } else { | |
| 1965 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, | |
| 1966 &maxWinding, &sumWinding); | |
| 1967 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); | |
| 1968 } | |
| 1969 nextAngle->setLastMarked(last); | |
| 1970 } | |
| 1971 | |
| 1972 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne
xtAngle, | |
| 1973 SkOpAngle::IncludeType includeType) { | |
| 1974 const SkOpSegment* baseSegment = baseAngle->segment(); | |
| 1975 int sumMiWinding = baseSegment->updateWinding(baseAngle); | |
| 1976 int sumSuWinding; | |
| 1977 bool binary = includeType >= SkOpAngle::kBinarySingle; | |
| 1978 if (binary) { | |
| 1979 sumSuWinding = baseSegment->updateOppWinding(baseAngle); | |
| 1980 if (baseSegment->operand()) { | |
| 1981 SkTSwap<int>(sumMiWinding, sumSuWinding); | |
| 1982 } | |
| 1983 } | |
| 1984 SkOpSegment* nextSegment = nextAngle->segment(); | |
| 1985 int maxWinding, sumWinding; | |
| 1986 SkOpSpan* last; | |
| 1987 if (binary) { | |
| 1988 int oppMaxWinding, oppSumWinding; | |
| 1989 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, | |
| 1990 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); | |
| 1991 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, | |
| 1992 nextAngle); | |
| 1993 } else { | |
| 1994 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, | |
| 1995 &maxWinding, &sumWinding); | |
| 1996 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); | |
| 1997 } | |
| 1998 nextAngle->setLastMarked(last); | |
| 1999 } | |
| 2000 | |
| 2001 bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const { | |
| 2002 int step = index < endIndex ? 1 : -1; | |
| 2003 do { | |
| 2004 const SkOpSpan& span = this->span(index); | |
| 2005 if (span.fPt == pt) { | |
| 2006 const SkOpSpan& endSpan = this->span(endIndex); | |
| 2007 return span.fT == endSpan.fT && pt != endSpan.fPt; | |
| 2008 } | |
| 2009 index += step; | |
| 2010 } while (index != endIndex); | |
| 2011 return false; | |
| 2012 } | |
| 2013 | |
| 2014 bool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) c
onst { | |
| 2015 int count = this->count(); | |
| 2016 for (int index = 0; index < count; ++index) { | |
| 2017 const SkOpSpan& span = fTs[index]; | |
| 2018 if (t < span.fT) { | |
| 2019 return false; | |
| 2020 } | |
| 2021 if (t == span.fT) { | |
| 2022 if (other != span.fOther) { | |
| 2023 continue; | |
| 2024 } | |
| 2025 if (other->fVerb != SkPath::kCubic_Verb) { | |
| 2026 return true; | |
| 2027 } | |
| 2028 if (!other->fLoop) { | |
| 2029 return true; | |
| 2030 } | |
| 2031 double otherMidT = (otherT + span.fOtherT) / 2; | |
| 2032 SkPoint otherPt = other->ptAtT(otherMidT); | |
| 2033 return SkDPoint::ApproximatelyEqual(span.fPt, otherPt); | |
| 2034 } | |
| 2035 } | |
| 2036 return false; | |
| 2037 } | |
| 2038 | |
| 2039 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, | |
| 2040 bool* hitSomething, double mid, bool opp, bool cur
rent) const { | |
| 2041 SkScalar bottom = fBounds.fBottom; | 660 SkScalar bottom = fBounds.fBottom; |
| 2042 int bestTIndex = -1; | 661 *vertical = false; |
| 2043 if (bottom <= *bestY) { | 662 if (bottom <= *bestY) { |
| 2044 return bestTIndex; | 663 return NULL; |
| 2045 } | 664 } |
| 2046 SkScalar top = fBounds.fTop; | 665 SkScalar top = fBounds.fTop; |
| 2047 if (top >= basePt.fY) { | 666 if (top >= basePt.fY) { |
| 2048 return bestTIndex; | 667 return NULL; |
| 2049 } | 668 } |
| 2050 if (fBounds.fLeft > basePt.fX) { | 669 if (fBounds.fLeft > basePt.fX) { |
| 2051 return bestTIndex; | 670 return NULL; |
| 2052 } | 671 } |
| 2053 if (fBounds.fRight < basePt.fX) { | 672 if (fBounds.fRight < basePt.fX) { |
| 2054 return bestTIndex; | 673 return NULL; |
| 2055 } | 674 } |
| 2056 if (fBounds.fLeft == fBounds.fRight) { | 675 if (fBounds.fLeft == fBounds.fRight) { |
| 2057 // if vertical, and directly above test point, wait for another one | 676 // if vertical, and directly above test point, wait for another one |
| 2058 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTInde
x; | 677 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft); |
| 678 return NULL; |
| 2059 } | 679 } |
| 2060 // intersect ray starting at basePt with edge | 680 // intersect ray starting at basePt with edge |
| 2061 SkIntersections intersections; | 681 SkIntersections intersections; |
| 2062 // OPTIMIZE: use specialty function that intersects ray with curve, | 682 // OPTIMIZE: use specialty function that intersects ray with curve, |
| 2063 // returning t values only for curve (we don't care about t on ray) | 683 // returning t values only for curve (we don't care about t on ray) |
| 2064 intersections.allowNear(false); | 684 intersections.allowNear(false); |
| 2065 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) | 685 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) |
| 2066 (fPts, top, bottom, basePt.fX, false); | 686 (fPts, top, bottom, basePt.fX, false); |
| 2067 if (pts == 0 || (current && pts == 1)) { | 687 if (pts == 0 || (current && pts == 1)) { |
| 2068 return bestTIndex; | 688 return NULL; |
| 2069 } | 689 } |
| 2070 if (current) { | 690 if (current) { |
| 2071 SkASSERT(pts > 1); | 691 SkASSERT(pts > 1); |
| 2072 int closestIdx = 0; | 692 int closestIdx = 0; |
| 2073 double closest = fabs(intersections[0][0] - mid); | 693 double closest = fabs(intersections[0][0] - mid); |
| 2074 for (int idx = 1; idx < pts; ++idx) { | 694 for (int idx = 1; idx < pts; ++idx) { |
| 2075 double test = fabs(intersections[0][idx] - mid); | 695 double test = fabs(intersections[0][idx] - mid); |
| 2076 if (closest > test) { | 696 if (closest > test) { |
| 2077 closestIdx = idx; | 697 closestIdx = idx; |
| 2078 closest = test; | 698 closest = test; |
| 2079 } | 699 } |
| 2080 } | 700 } |
| 2081 intersections.quickRemoveOne(closestIdx, --pts); | 701 intersections.quickRemoveOne(closestIdx, --pts); |
| 2082 } | 702 } |
| 2083 double bestT = -1; | 703 double bestT = -1; |
| 2084 for (int index = 0; index < pts; ++index) { | 704 for (int index = 0; index < pts; ++index) { |
| 2085 double foundT = intersections[0][index]; | 705 double foundT = intersections[0][index]; |
| 2086 if (approximately_less_than_zero(foundT) | 706 if (approximately_less_than_zero(foundT) |
| 2087 || approximately_greater_than_one(foundT)) { | 707 || approximately_greater_than_one(foundT)) { |
| 2088 continue; | 708 continue; |
| 2089 } | 709 } |
| 2090 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fo
undT).fY; | 710 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fo
undT).fY; |
| 2091 if (approximately_negative(testY - *bestY) | 711 if (approximately_negative(testY - *bestY) |
| 2092 || approximately_negative(basePt.fY - testY)) { | 712 || approximately_negative(basePt.fY - testY)) { |
| 2093 continue; | 713 continue; |
| 2094 } | 714 } |
| 2095 if (pts > 1 && fVerb == SkPath::kLine_Verb) { | 715 if (pts > 1 && fVerb == SkPath::kLine_Verb) { |
| 2096 return SK_MinS32; // if the intersection is edge on, wait for anoth
er one | 716 *vertical = true; |
| 717 return NULL; // if the intersection is edge on, wait for another on
e |
| 2097 } | 718 } |
| 2098 if (fVerb > SkPath::kLine_Verb) { | 719 if (fVerb > SkPath::kLine_Verb) { |
| 2099 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, f
oundT).fX; | 720 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, f
oundT).fX; |
| 2100 if (approximately_zero(dx)) { | 721 if (approximately_zero(dx)) { |
| 2101 return SK_MinS32; // hit vertical, wait for another one | 722 *vertical = true; |
| 723 return NULL; // hit vertical, wait for another one |
| 2102 } | 724 } |
| 2103 } | 725 } |
| 2104 *bestY = testY; | 726 *bestY = testY; |
| 2105 bestT = foundT; | 727 bestT = foundT; |
| 2106 } | 728 } |
| 2107 if (bestT < 0) { | 729 if (bestT < 0) { |
| 2108 return bestTIndex; | 730 return NULL; |
| 2109 } | 731 } |
| 2110 SkASSERT(bestT >= 0); | 732 SkASSERT(bestT >= 0); |
| 2111 SkASSERT(bestT <= 1); | 733 SkASSERT(bestT < 1); |
| 2112 int start; | 734 SkOpSpanBase* testTSpanBase = &this->fHead; |
| 2113 int end = 0; | 735 SkOpSpanBase* nextTSpan; |
| 736 double endT = 0; |
| 2114 do { | 737 do { |
| 2115 start = end; | 738 nextTSpan = testTSpanBase->upCast()->next(); |
| 2116 end = nextSpan(start, 1); | 739 endT = nextTSpan->t(); |
| 2117 } while (fTs[end].fT < bestT); | 740 if (endT >= bestT) { |
| 2118 // FIXME: see next candidate for a better pattern to find the next start/end
pair | 741 break; |
| 2119 while (start + 1 < end && fTs[start].fDone) { | 742 } |
| 2120 ++start; | 743 testTSpanBase = nextTSpan; |
| 2121 } | 744 } while (testTSpanBase); |
| 2122 if (!isCanceled(start)) { | 745 SkOpSpan* bestTSpan = NULL; |
| 746 SkOpSpan* testTSpan = testTSpanBase->upCast(); |
| 747 if (!testTSpan->isCanceled()) { |
| 2123 *hitT = bestT; | 748 *hitT = bestT; |
| 2124 bestTIndex = start; | 749 bestTSpan = testTSpan; |
| 2125 *hitSomething = true; | 750 *hitSomething = true; |
| 2126 } | 751 } |
| 2127 return bestTIndex; | 752 return bestTSpan; |
| 2128 } | 753 } |
| 2129 | 754 |
| 2130 bool SkOpSegment::decrementSpan(SkOpSpan* span) { | 755 void SkOpSegment::detach(const SkOpSpan* span) { |
| 2131 SkASSERT(span->fWindValue > 0); | 756 if (span->done()) { |
| 2132 if (--(span->fWindValue) == 0) { | 757 --this->fDoneCount; |
| 2133 if (!span->fOppValue && !span->fDone) { | 758 } |
| 2134 span->fDone = true; | 759 --this->fCount; |
| 2135 ++fDoneSpans; | 760 } |
| 2136 return true; | 761 |
| 762 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) { |
| 763 SkDPoint testPt = this->dPtAtT(t); |
| 764 SkDLine testPerp = {{ testPt, testPt }}; |
| 765 SkDVector slope = this->dSlopeAtT(t); |
| 766 testPerp[1].fX += slope.fY; |
| 767 testPerp[1].fY -= slope.fX; |
| 768 SkIntersections i; |
| 769 SkOpSegment* oppSegment = oppAngle->segment(); |
| 770 int oppPtCount = SkPathOpsVerbToPoints(oppSegment->verb()); |
| 771 (*CurveIntersectRay[oppPtCount])(oppSegment->pts(), testPerp, &i); |
| 772 double closestDistSq = SK_ScalarInfinity; |
| 773 for (int index = 0; index < i.used(); ++index) { |
| 774 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
{ |
| 775 continue; |
| 776 } |
| 777 double testDistSq = testPt.distanceSquared(i.pt(index)); |
| 778 if (closestDistSq > testDistSq) { |
| 779 closestDistSq = testDistSq; |
| 2137 } | 780 } |
| 2138 } | 781 } |
| 2139 return false; | 782 return closestDistSq; |
| 2140 } | |
| 2141 | |
| 2142 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) { | |
| 2143 SkASSERT(!span->fDone || span->fTiny || span->fSmall); | |
| 2144 span->fWindValue += windDelta; | |
| 2145 SkASSERT(span->fWindValue >= 0); | |
| 2146 span->fOppValue += oppDelta; | |
| 2147 SkASSERT(span->fOppValue >= 0); | |
| 2148 if (fXor) { | |
| 2149 span->fWindValue &= 1; | |
| 2150 } | |
| 2151 if (fOppXor) { | |
| 2152 span->fOppValue &= 1; | |
| 2153 } | |
| 2154 if (!span->fWindValue && !span->fOppValue) { | |
| 2155 if (!span->fDone) { | |
| 2156 span->fDone = true; | |
| 2157 ++fDoneSpans; | |
| 2158 } | |
| 2159 return true; | |
| 2160 } | |
| 2161 return false; | |
| 2162 } | |
| 2163 | |
| 2164 const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const { | |
| 2165 const SkOpSpan* firstSpan = &thisSpan; // rewind to the start | |
| 2166 const SkOpSpan* beginSpan = fTs.begin(); | |
| 2167 const SkPoint& testPt = thisSpan.fPt; | |
| 2168 while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) { | |
| 2169 --firstSpan; | |
| 2170 } | |
| 2171 return *firstSpan; | |
| 2172 } | |
| 2173 | |
| 2174 const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const { | |
| 2175 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small | |
| 2176 const SkOpSpan* lastSpan = &thisSpan; // find the end | |
| 2177 const SkPoint& testPt = thisSpan.fPt; | |
| 2178 while (lastSpan < endSpan && lastSpan[1].fPt == testPt) { | |
| 2179 ++lastSpan; | |
| 2180 } | |
| 2181 return *lastSpan; | |
| 2182 } | |
| 2183 | |
| 2184 // with a loop, the comparison is move involved | |
| 2185 // scan backwards and forwards to count all matching points | |
| 2186 // (verify that there are twp scans marked as loops) | |
| 2187 // compare that against 2 matching scans for loop plus other results | |
| 2188 bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts)
{ | |
| 2189 const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the star
t | |
| 2190 const SkOpSpan& lastSpan = this->lastSpan(thisSpan); // find the end | |
| 2191 double firstLoopT = -1, lastLoopT = -1; | |
| 2192 const SkOpSpan* testSpan = &firstSpan - 1; | |
| 2193 while (++testSpan <= &lastSpan) { | |
| 2194 if (testSpan->fLoop) { | |
| 2195 firstLoopT = testSpan->fT; | |
| 2196 break; | |
| 2197 } | |
| 2198 } | |
| 2199 testSpan = &lastSpan + 1; | |
| 2200 while (--testSpan >= &firstSpan) { | |
| 2201 if (testSpan->fLoop) { | |
| 2202 lastLoopT = testSpan->fT; | |
| 2203 break; | |
| 2204 } | |
| 2205 } | |
| 2206 SkASSERT((firstLoopT == -1) == (lastLoopT == -1)); | |
| 2207 if (firstLoopT == -1) { | |
| 2208 return false; | |
| 2209 } | |
| 2210 SkASSERT(firstLoopT < lastLoopT); | |
| 2211 testSpan = &firstSpan - 1; | |
| 2212 smallCounts[0] = smallCounts[1] = 0; | |
| 2213 while (++testSpan <= &lastSpan) { | |
| 2214 SkASSERT(approximately_equal(testSpan->fT, firstLoopT) + | |
| 2215 approximately_equal(testSpan->fT, lastLoopT) == 1); | |
| 2216 smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++; | |
| 2217 } | |
| 2218 return true; | |
| 2219 } | |
| 2220 | |
| 2221 double SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double
min, double max, | |
| 2222 double hiEnd, const SkOpSegment* other, int thisStart) { | |
| 2223 if (max >= hiEnd) { | |
| 2224 return -1; | |
| 2225 } | |
| 2226 int end = findOtherT(hiEnd, ref); | |
| 2227 if (end < 0) { | |
| 2228 return -1; | |
| 2229 } | |
| 2230 double tHi = span(end).fT; | |
| 2231 double tLo, refLo; | |
| 2232 if (thisStart >= 0) { | |
| 2233 tLo = span(thisStart).fT; | |
| 2234 refLo = min; | |
| 2235 } else { | |
| 2236 int start1 = findOtherT(loEnd, ref); | |
| 2237 SkASSERT(start1 >= 0); | |
| 2238 tLo = span(start1).fT; | |
| 2239 refLo = loEnd; | |
| 2240 } | |
| 2241 double missingT = (max - refLo) / (hiEnd - refLo); | |
| 2242 missingT = tLo + missingT * (tHi - tLo); | |
| 2243 return missingT; | |
| 2244 } | |
| 2245 | |
| 2246 double SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, doub
le min, double max, | |
| 2247 double hiEnd, const SkOpSegment* other, int thisEnd) { | |
| 2248 if (min <= loEnd) { | |
| 2249 return -1; | |
| 2250 } | |
| 2251 int start = findOtherT(loEnd, ref); | |
| 2252 if (start < 0) { | |
| 2253 return -1; | |
| 2254 } | |
| 2255 double tLo = span(start).fT; | |
| 2256 double tHi, refHi; | |
| 2257 if (thisEnd >= 0) { | |
| 2258 tHi = span(thisEnd).fT; | |
| 2259 refHi = max; | |
| 2260 } else { | |
| 2261 int end1 = findOtherT(hiEnd, ref); | |
| 2262 if (end1 < 0) { | |
| 2263 return -1; | |
| 2264 } | |
| 2265 tHi = span(end1).fT; | |
| 2266 refHi = hiEnd; | |
| 2267 } | |
| 2268 double missingT = (min - loEnd) / (refHi - loEnd); | |
| 2269 missingT = tLo + missingT * (tHi - tLo); | |
| 2270 return missingT; | |
| 2271 } | |
| 2272 | |
| 2273 // see if spans with two or more intersections have the same number on the other
end | |
| 2274 void SkOpSegment::checkDuplicates() { | |
| 2275 debugValidate(); | |
| 2276 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; | |
| 2277 int index; | |
| 2278 int endIndex = 0; | |
| 2279 bool endFound; | |
| 2280 do { | |
| 2281 index = endIndex; | |
| 2282 endIndex = nextExactSpan(index, 1); | |
| 2283 if ((endFound = endIndex < 0)) { | |
| 2284 endIndex = count(); | |
| 2285 } | |
| 2286 int dupCount = endIndex - index; | |
| 2287 if (dupCount < 2) { | |
| 2288 continue; | |
| 2289 } | |
| 2290 do { | |
| 2291 const SkOpSpan* thisSpan = &fTs[index]; | |
| 2292 if (thisSpan->fNear) { | |
| 2293 continue; | |
| 2294 } | |
| 2295 SkOpSegment* other = thisSpan->fOther; | |
| 2296 int oIndex = thisSpan->fOtherIndex; | |
| 2297 int oStart = other->nextExactSpan(oIndex, -1) + 1; | |
| 2298 int oEnd = other->nextExactSpan(oIndex, 1); | |
| 2299 if (oEnd < 0) { | |
| 2300 oEnd = other->count(); | |
| 2301 } | |
| 2302 int oCount = oEnd - oStart; | |
| 2303 // force the other to match its t and this pt if not on an end point | |
| 2304 if (oCount != dupCount) { | |
| 2305 MissingSpan& missing = missingSpans.push_back(); | |
| 2306 missing.fOther = NULL; | |
| 2307 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); | |
| 2308 missing.fPt = thisSpan->fPt; | |
| 2309 const SkOpSpan& oSpan = other->span(oIndex); | |
| 2310 if (oCount > dupCount) { | |
| 2311 missing.fSegment = this; | |
| 2312 missing.fT = thisSpan->fT; | |
| 2313 other->checkLinks(&oSpan, &missingSpans); | |
| 2314 } else { | |
| 2315 missing.fSegment = other; | |
| 2316 missing.fT = oSpan.fT; | |
| 2317 checkLinks(thisSpan, &missingSpans); | |
| 2318 } | |
| 2319 if (!missingSpans.back().fOther) { | |
| 2320 missingSpans.pop_back(); | |
| 2321 } | |
| 2322 } | |
| 2323 } while (++index < endIndex); | |
| 2324 } while (!endFound); | |
| 2325 int missingCount = missingSpans.count(); | |
| 2326 if (missingCount == 0) { | |
| 2327 return; | |
| 2328 } | |
| 2329 SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence; | |
| 2330 for (index = 0; index < missingCount; ++index) { | |
| 2331 MissingSpan& missing = missingSpans[index]; | |
| 2332 SkOpSegment* missingOther = missing.fOther; | |
| 2333 if (missing.fSegment == missing.fOther) { | |
| 2334 continue; | |
| 2335 } | |
| 2336 #if 0 // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 bu
t breaks | |
| 2337 // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't unde
rstand why | |
| 2338 if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOth
erT)) { | |
| 2339 #if DEBUG_DUPLICATES | |
| 2340 SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSe
gment->fID, | |
| 2341 missing.fT, missing.fOther->fID, missing.fOtherT); | |
| 2342 #endif | |
| 2343 continue; | |
| 2344 } | |
| 2345 if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing
.fT)) { | |
| 2346 #if DEBUG_DUPLICATES | |
| 2347 SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOt
her->fID, | |
| 2348 missing.fOtherT, missing.fSegment->fID, missing.fT); | |
| 2349 #endif | |
| 2350 continue; | |
| 2351 } | |
| 2352 #endif | |
| 2353 // skip if adding would insert point into an existing coincindent span | |
| 2354 if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther) | |
| 2355 && missingOther->inCoincidentSpan(missing.fOtherT, this)) { | |
| 2356 continue; | |
| 2357 } | |
| 2358 // skip if the created coincident spans are small | |
| 2359 if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOt
her) | |
| 2360 && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, m
issing.fSegment)) { | |
| 2361 continue; | |
| 2362 } | |
| 2363 const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOt
her, | |
| 2364 missing.fOtherT, false, missing.fPt); | |
| 2365 if (added && added->fSmall) { | |
| 2366 missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence)
; | |
| 2367 } | |
| 2368 } | |
| 2369 for (index = 0; index < missingCount; ++index) { | |
| 2370 MissingSpan& missing = missingSpans[index]; | |
| 2371 missing.fSegment->fixOtherTIndex(); | |
| 2372 missing.fOther->fixOtherTIndex(); | |
| 2373 } | |
| 2374 for (index = 0; index < missingCoincidence.count(); ++index) { | |
| 2375 MissingSpan& missing = missingCoincidence[index]; | |
| 2376 missing.fSegment->fixOtherTIndex(); | |
| 2377 } | |
| 2378 debugValidate(); | |
| 2379 } | |
| 2380 | |
| 2381 // look to see if the curve end intersects an intermediary that intersects the o
ther | |
| 2382 bool SkOpSegment::checkEnds() { | |
| 2383 debugValidate(); | |
| 2384 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; | |
| 2385 int count = fTs.count(); | |
| 2386 for (int index = 0; index < count; ++index) { | |
| 2387 const SkOpSpan& span = fTs[index]; | |
| 2388 double otherT = span.fOtherT; | |
| 2389 if (otherT != 0 && otherT != 1) { // only check ends | |
| 2390 continue; | |
| 2391 } | |
| 2392 const SkOpSegment* other = span.fOther; | |
| 2393 // peek start/last describe the range of spans that match the other t of
this span | |
| 2394 int peekStart = span.fOtherIndex; | |
| 2395 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT) | |
| 2396 ; | |
| 2397 int otherCount = other->fTs.count(); | |
| 2398 int peekLast = span.fOtherIndex; | |
| 2399 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT) | |
| 2400 ; | |
| 2401 if (++peekStart == --peekLast) { // if there isn't a range, there's noth
ing to do | |
| 2402 continue; | |
| 2403 } | |
| 2404 // t start/last describe the range of spans that match the t of this spa
n | |
| 2405 double t = span.fT; | |
| 2406 double tBottom = -1; | |
| 2407 int tStart = -1; | |
| 2408 int tLast = count; | |
| 2409 bool lastSmall = false; | |
| 2410 double afterT = t; | |
| 2411 for (int inner = 0; inner < count; ++inner) { | |
| 2412 double innerT = fTs[inner].fT; | |
| 2413 if (innerT <= t && innerT > tBottom) { | |
| 2414 if (innerT < t || !lastSmall) { | |
| 2415 tStart = inner - 1; | |
| 2416 } | |
| 2417 tBottom = innerT; | |
| 2418 } | |
| 2419 if (innerT > afterT) { | |
| 2420 if (t == afterT && lastSmall) { | |
| 2421 afterT = innerT; | |
| 2422 } else { | |
| 2423 tLast = inner; | |
| 2424 break; | |
| 2425 } | |
| 2426 } | |
| 2427 lastSmall = innerT <= t ? fTs[inner].fSmall : false; | |
| 2428 } | |
| 2429 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { | |
| 2430 if (peekIndex == span.fOtherIndex) { // skip the other span pointed
to by this span | |
| 2431 continue; | |
| 2432 } | |
| 2433 const SkOpSpan& peekSpan = other->fTs[peekIndex]; | |
| 2434 SkOpSegment* match = peekSpan.fOther; | |
| 2435 if (match->done()) { | |
| 2436 continue; // if the edge has already been eaten (likely coincid
ence), ignore it | |
| 2437 } | |
| 2438 const double matchT = peekSpan.fOtherT; | |
| 2439 // see if any of the spans match the other spans | |
| 2440 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) { | |
| 2441 const SkOpSpan& tSpan = fTs[tIndex]; | |
| 2442 if (tSpan.fOther == match) { | |
| 2443 if (tSpan.fOtherT == matchT) { | |
| 2444 goto nextPeekIndex; | |
| 2445 } | |
| 2446 double midT = (tSpan.fOtherT + matchT) / 2; | |
| 2447 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) { | |
| 2448 goto nextPeekIndex; | |
| 2449 } | |
| 2450 } | |
| 2451 } | |
| 2452 if (missingSpans.count() > 0) { | |
| 2453 const MissingSpan& lastMissing = missingSpans.back(); | |
| 2454 if (lastMissing.fT == t | |
| 2455 && lastMissing.fOther == match | |
| 2456 && lastMissing.fOtherT == matchT) { | |
| 2457 SkASSERT(SkDPoint::ApproximatelyEqual(lastMissing.fPt, peekS
pan.fPt)); | |
| 2458 continue; | |
| 2459 } | |
| 2460 } | |
| 2461 if (this == match) { | |
| 2462 return false; // extremely large paths can trigger this | |
| 2463 } | |
| 2464 #if DEBUG_CHECK_ALIGN | |
| 2465 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%
1.9g)\n", | |
| 2466 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, p
eekSpan.fPt.fY); | |
| 2467 #endif | |
| 2468 // this segment is missing a entry that the other contains | |
| 2469 // remember so we can add the missing one and recompute the indices | |
| 2470 { | |
| 2471 MissingSpan& missing = missingSpans.push_back(); | |
| 2472 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); | |
| 2473 missing.fT = t; | |
| 2474 SkASSERT(this != match); | |
| 2475 missing.fOther = match; | |
| 2476 missing.fOtherT = matchT; | |
| 2477 missing.fPt = peekSpan.fPt; | |
| 2478 } | |
| 2479 break; | |
| 2480 nextPeekIndex: | |
| 2481 ; | |
| 2482 } | |
| 2483 } | |
| 2484 if (missingSpans.count() == 0) { | |
| 2485 debugValidate(); | |
| 2486 return true; | |
| 2487 } | |
| 2488 debugValidate(); | |
| 2489 int missingCount = missingSpans.count(); | |
| 2490 for (int index = 0; index < missingCount; ++index) { | |
| 2491 MissingSpan& missing = missingSpans[index]; | |
| 2492 if (this != missing.fOther) { | |
| 2493 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing
.fPt); | |
| 2494 } | |
| 2495 } | |
| 2496 fixOtherTIndex(); | |
| 2497 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq
ue segments to | |
| 2498 // avoid this | |
| 2499 for (int index = 0; index < missingCount; ++index) { | |
| 2500 missingSpans[index].fOther->fixOtherTIndex(); | |
| 2501 } | |
| 2502 debugValidate(); | |
| 2503 return true; | |
| 2504 } | |
| 2505 | |
| 2506 void SkOpSegment::checkLinks(const SkOpSpan* base, | |
| 2507 SkTArray<MissingSpan, true>* missingSpans) const { | |
| 2508 const SkOpSpan* first = fTs.begin(); | |
| 2509 const SkOpSpan* last = fTs.end() - 1; | |
| 2510 SkASSERT(base >= first && last >= base); | |
| 2511 const SkOpSegment* other = base->fOther; | |
| 2512 const SkOpSpan* oFirst = other->fTs.begin(); | |
| 2513 const SkOpSpan* oLast = other->fTs.end() - 1; | |
| 2514 const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex]; | |
| 2515 const SkOpSpan* test = base; | |
| 2516 const SkOpSpan* missing = NULL; | |
| 2517 while (test > first && (--test)->fPt == base->fPt) { | |
| 2518 if (this == test->fOther) { | |
| 2519 continue; | |
| 2520 } | |
| 2521 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans); | |
| 2522 } | |
| 2523 test = base; | |
| 2524 while (test < last && (++test)->fPt == base->fPt) { | |
| 2525 SkASSERT(this != test->fOther || test->fLoop); | |
| 2526 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans); | |
| 2527 } | |
| 2528 } | |
| 2529 | |
| 2530 // see if spans with two or more intersections all agree on common t and point v
alues | |
| 2531 void SkOpSegment::checkMultiples() { | |
| 2532 debugValidate(); | |
| 2533 int index; | |
| 2534 int end = 0; | |
| 2535 while (fTs[++end].fT == 0) | |
| 2536 ; | |
| 2537 while (fTs[end].fT < 1) { | |
| 2538 int start = index = end; | |
| 2539 end = nextExactSpan(index, 1); | |
| 2540 if (end <= index) { | |
| 2541 return; // buffer overflow example triggers this | |
| 2542 } | |
| 2543 if (index + 1 == end) { | |
| 2544 continue; | |
| 2545 } | |
| 2546 // force the duplicates to agree on t and pt if not on the end | |
| 2547 SkOpSpan& span = fTs[index]; | |
| 2548 double thisT = span.fT; | |
| 2549 const SkPoint& thisPt = span.fPt; | |
| 2550 span.fMultiple = true; | |
| 2551 bool aligned = false; | |
| 2552 while (++index < end) { | |
| 2553 aligned |= alignSpan(index, thisT, thisPt); | |
| 2554 } | |
| 2555 if (aligned) { | |
| 2556 alignSpanState(start, end); | |
| 2557 } | |
| 2558 fMultiples = true; | |
| 2559 } | |
| 2560 debugValidate(); | |
| 2561 } | |
| 2562 | |
| 2563 void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan, | |
| 2564 const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingP
tr, | |
| 2565 SkTArray<MissingSpan, true>* missingSpans) { | |
| 2566 SkASSERT(oSpan->fPt == test->fPt); | |
| 2567 const SkOpSpan* oTest = oSpan; | |
| 2568 while (oTest > oFirst && (--oTest)->fPt == test->fPt) { | |
| 2569 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) { | |
| 2570 return; | |
| 2571 } | |
| 2572 } | |
| 2573 oTest = oSpan; | |
| 2574 while (oTest < oLast && (++oTest)->fPt == test->fPt) { | |
| 2575 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) { | |
| 2576 return; | |
| 2577 } | |
| 2578 } | |
| 2579 if (*missingPtr) { | |
| 2580 missingSpans->push_back(); | |
| 2581 } | |
| 2582 MissingSpan& lastMissing = missingSpans->back(); | |
| 2583 if (*missingPtr) { | |
| 2584 lastMissing = missingSpans->end()[-2]; | |
| 2585 } | |
| 2586 *missingPtr = test; | |
| 2587 lastMissing.fOther = test->fOther; | |
| 2588 lastMissing.fOtherT = test->fOtherT; | |
| 2589 } | |
| 2590 | |
| 2591 bool SkOpSegment::checkSmall(int index) const { | |
| 2592 if (fTs[index].fSmall) { | |
| 2593 return true; | |
| 2594 } | |
| 2595 double tBase = fTs[index].fT; | |
| 2596 while (index > 0 && precisely_negative(tBase - fTs[--index].fT)) | |
| 2597 ; | |
| 2598 return fTs[index].fSmall; | |
| 2599 } | |
| 2600 | |
| 2601 // a pair of curves may turn into coincident lines -- small may be a hint that t
hat happened | |
| 2602 // if a cubic contains a loop, the counts must be adjusted | |
| 2603 void SkOpSegment::checkSmall() { | |
| 2604 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; | |
| 2605 const SkOpSpan* beginSpan = fTs.begin(); | |
| 2606 const SkOpSpan* thisSpan = beginSpan - 1; | |
| 2607 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small | |
| 2608 while (++thisSpan < endSpan) { | |
| 2609 if (!thisSpan->fSmall) { | |
| 2610 continue; | |
| 2611 } | |
| 2612 if (!thisSpan->fWindValue) { | |
| 2613 continue; | |
| 2614 } | |
| 2615 const SkOpSpan& firstSpan = this->firstSpan(*thisSpan); | |
| 2616 const SkOpSpan& lastSpan = this->lastSpan(*thisSpan); | |
| 2617 const SkOpSpan* nextSpan = &firstSpan + 1; | |
| 2618 ptrdiff_t smallCount = &lastSpan - &firstSpan + 1; | |
| 2619 SkASSERT(1 <= smallCount && smallCount < count()); | |
| 2620 if (smallCount <= 1 && !nextSpan->fSmall) { | |
| 2621 SkASSERT(1 == smallCount); | |
| 2622 checkSmallCoincidence(firstSpan, NULL); | |
| 2623 continue; | |
| 2624 } | |
| 2625 // at this point, check for missing computed intersections | |
| 2626 const SkPoint& testPt = firstSpan.fPt; | |
| 2627 thisSpan = &firstSpan - 1; | |
| 2628 SkOpSegment* other = NULL; | |
| 2629 while (++thisSpan <= &lastSpan) { | |
| 2630 other = thisSpan->fOther; | |
| 2631 if (other != this) { | |
| 2632 break; | |
| 2633 } | |
| 2634 } | |
| 2635 SkASSERT(other != this); | |
| 2636 int oIndex = thisSpan->fOtherIndex; | |
| 2637 const SkOpSpan& oSpan = other->span(oIndex); | |
| 2638 const SkOpSpan& oFirstSpan = other->firstSpan(oSpan); | |
| 2639 const SkOpSpan& oLastSpan = other->lastSpan(oSpan); | |
| 2640 ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1; | |
| 2641 if (fLoop) { | |
| 2642 int smallCounts[2]; | |
| 2643 SkASSERT(!other->fLoop); // FIXME: we need more complicated logic f
or pair of loops | |
| 2644 if (calcLoopSpanCount(*thisSpan, smallCounts)) { | |
| 2645 if (smallCounts[0] && oCount != smallCounts[0]) { | |
| 2646 SkASSERT(0); // FIXME: need a working test case to properly
code & debug | |
| 2647 } | |
| 2648 if (smallCounts[1] && oCount != smallCounts[1]) { | |
| 2649 SkASSERT(0); // FIXME: need a working test case to properly
code & debug | |
| 2650 } | |
| 2651 goto nextSmallCheck; | |
| 2652 } | |
| 2653 } | |
| 2654 if (other->fLoop) { | |
| 2655 int otherCounts[2]; | |
| 2656 if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) { | |
| 2657 if (otherCounts[0] && otherCounts[0] != smallCount) { | |
| 2658 SkASSERT(0); // FIXME: need a working test case to properly
code & debug | |
| 2659 } | |
| 2660 if (otherCounts[1] && otherCounts[1] != smallCount) { | |
| 2661 SkASSERT(0); // FIXME: need a working test case to properly
code & debug | |
| 2662 } | |
| 2663 goto nextSmallCheck; | |
| 2664 } | |
| 2665 } | |
| 2666 if (oCount != smallCount) { // check if number of pts in this match oth
er | |
| 2667 MissingSpan& missing = missingSpans.push_back(); | |
| 2668 missing.fOther = NULL; | |
| 2669 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); | |
| 2670 missing.fPt = testPt; | |
| 2671 const SkOpSpan& oSpan = other->span(oIndex); | |
| 2672 if (oCount > smallCount) { | |
| 2673 missing.fSegment = this; | |
| 2674 missing.fT = thisSpan->fT; | |
| 2675 other->checkLinks(&oSpan, &missingSpans); | |
| 2676 } else { | |
| 2677 missing.fSegment = other; | |
| 2678 missing.fT = oSpan.fT; | |
| 2679 checkLinks(thisSpan, &missingSpans); | |
| 2680 } | |
| 2681 if (!missingSpans.back().fOther || missing.fSegment->done()) { | |
| 2682 missingSpans.pop_back(); | |
| 2683 } | |
| 2684 } | |
| 2685 nextSmallCheck: | |
| 2686 thisSpan = &lastSpan; | |
| 2687 } | |
| 2688 int missingCount = missingSpans.count(); | |
| 2689 for (int index = 0; index < missingCount; ++index) { | |
| 2690 MissingSpan& missing = missingSpans[index]; | |
| 2691 SkOpSegment* missingOther = missing.fOther; | |
| 2692 // note that add t pair may edit span arrays, so prior pointers to spans
are no longer valid | |
| 2693 if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOther
T, false, | |
| 2694 missing.fPt)) { | |
| 2695 continue; | |
| 2696 } | |
| 2697 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, miss
ing.fSegment); | |
| 2698 const SkOpSpan& otherSpan = missingOther->span(otherTIndex); | |
| 2699 if (otherSpan.fSmall) { | |
| 2700 const SkOpSpan* nextSpan = &otherSpan; | |
| 2701 if (nextSpan->fPt == missing.fPt) { | |
| 2702 continue; | |
| 2703 } | |
| 2704 do { | |
| 2705 ++nextSpan; | |
| 2706 } while (nextSpan->fSmall); | |
| 2707 if (nextSpan->fT == 1) { | |
| 2708 continue; | |
| 2709 } | |
| 2710 SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpa
n->fPt, | |
| 2711 nextSpan->fT, missingOther)); | |
| 2712 } else if (otherSpan.fT > 0) { | |
| 2713 const SkOpSpan* priorSpan = &otherSpan; | |
| 2714 do { | |
| 2715 --priorSpan; | |
| 2716 } while (priorSpan->fT == otherSpan.fT); | |
| 2717 if (priorSpan->fSmall) { | |
| 2718 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missin
gOther); | |
| 2719 } | |
| 2720 } | |
| 2721 } | |
| 2722 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq
ue segments to | |
| 2723 // avoid this | |
| 2724 for (int index = 0; index < missingCount; ++index) { | |
| 2725 MissingSpan& missing = missingSpans[index]; | |
| 2726 missing.fSegment->fixOtherTIndex(); | |
| 2727 missing.fOther->fixOtherTIndex(); | |
| 2728 } | |
| 2729 debugValidate(); | |
| 2730 } | |
| 2731 | |
| 2732 void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span, | |
| 2733 SkTArray<MissingSpan, true>* checkMultiple) { | |
| 2734 SkASSERT(span.fSmall); | |
| 2735 if (0 && !span.fWindValue) { | |
| 2736 return; | |
| 2737 } | |
| 2738 SkASSERT(&span < fTs.end() - 1); | |
| 2739 const SkOpSpan* next = &span + 1; | |
| 2740 SkASSERT(!next->fSmall || checkMultiple); | |
| 2741 if (checkMultiple) { | |
| 2742 while (next->fSmall) { | |
| 2743 ++next; | |
| 2744 SkASSERT(next < fTs.end()); | |
| 2745 } | |
| 2746 } | |
| 2747 SkOpSegment* other = span.fOther; | |
| 2748 while (other != next->fOther) { | |
| 2749 if (!checkMultiple) { | |
| 2750 return; | |
| 2751 } | |
| 2752 const SkOpSpan* test = next + 1; | |
| 2753 if (test == fTs.end()) { | |
| 2754 return; | |
| 2755 } | |
| 2756 if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) { | |
| 2757 return; | |
| 2758 } | |
| 2759 next = test; | |
| 2760 } | |
| 2761 SkASSERT(span.fT < next->fT); | |
| 2762 int oStartIndex = other->findExactT(span.fOtherT, this); | |
| 2763 int oEndIndex = other->findExactT(next->fOtherT, this); | |
| 2764 // FIXME: be overly conservative by limiting this to the caller that allows
multiple smalls | |
| 2765 if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath:
:kLine_Verb) { | |
| 2766 SkPoint mid = ptAtT((span.fT + next->fT) / 2); | |
| 2767 const SkOpSpan& oSpanStart = other->fTs[oStartIndex]; | |
| 2768 const SkOpSpan& oSpanEnd = other->fTs[oEndIndex]; | |
| 2769 SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2); | |
| 2770 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { | |
| 2771 return; | |
| 2772 } | |
| 2773 } | |
| 2774 // FIXME: again, be overly conservative to avoid breaking existing tests | |
| 2775 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex] | |
| 2776 : other->fTs[oEndIndex]; | |
| 2777 if (checkMultiple && !oSpan.fSmall) { | |
| 2778 return; | |
| 2779 } | |
| 2780 // SkASSERT(oSpan.fSmall); | |
| 2781 if (oStartIndex < oEndIndex) { | |
| 2782 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other)); | |
| 2783 } else { | |
| 2784 addTCancel(span.fPt, next->fPt, other); | |
| 2785 } | |
| 2786 if (!checkMultiple) { | |
| 2787 return; | |
| 2788 } | |
| 2789 // check to see if either segment is coincident with a third segment -- if i
t is, and if | |
| 2790 // the opposite segment is not already coincident with the third, make it so | |
| 2791 // OPTIMIZE: to make this check easier, add coincident and cancel could set
a coincident bit | |
| 2792 if (span.fWindValue != 1 || span.fOppValue != 0) { | |
| 2793 // start here; | |
| 2794 // iterate through the spans, looking for the third coincident case | |
| 2795 // if we find one, we need to return state to the caller so that the ind
ices can be fixed | |
| 2796 // this also suggests that all of this function is fragile since it reli
es on a valid index | |
| 2797 } | |
| 2798 // probably should make this a common function rather than copy/paste code | |
| 2799 if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) { | |
| 2800 const SkOpSpan* oTest = &oSpan; | |
| 2801 while (--oTest >= other->fTs.begin()) { | |
| 2802 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)
) { | |
| 2803 break; | |
| 2804 } | |
| 2805 SkOpSegment* testOther = oTest->fOther; | |
| 2806 SkASSERT(testOther != this); | |
| 2807 // look in both directions to see if there is a coincident span | |
| 2808 const SkOpSpan* tTest = testOther->fTs.begin(); | |
| 2809 for (int testIndex = 0; testIndex < testOther->count(); ++testIndex)
{ | |
| 2810 if (tTest->fPt != span.fPt) { | |
| 2811 ++tTest; | |
| 2812 continue; | |
| 2813 } | |
| 2814 if (testOther->verb() != SkPath::kLine_Verb | |
| 2815 || other->verb() != SkPath::kLine_Verb) { | |
| 2816 SkPoint mid = ptAtT((span.fT + next->fT) / 2); | |
| 2817 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2
); | |
| 2818 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { | |
| 2819 continue; | |
| 2820 } | |
| 2821 } | |
| 2822 #if DEBUG_CONCIDENT | |
| 2823 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, t
estOther->fID, | |
| 2824 oTest->fOtherT, tTest->fT); | |
| 2825 #endif | |
| 2826 if (tTest->fT < oTest->fOtherT) { | |
| 2827 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT,
testOther)); | |
| 2828 } else { | |
| 2829 addTCancel(span.fPt, next->fPt, testOther); | |
| 2830 } | |
| 2831 MissingSpan missing; | |
| 2832 missing.fSegment = testOther; | |
| 2833 checkMultiple->push_back(missing); | |
| 2834 break; | |
| 2835 } | |
| 2836 } | |
| 2837 oTest = &oSpan; | |
| 2838 while (++oTest < other->fTs.end()) { | |
| 2839 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)
) { | |
| 2840 break; | |
| 2841 } | |
| 2842 | |
| 2843 } | |
| 2844 } | |
| 2845 } | |
| 2846 | |
| 2847 // if pair of spans on either side of tiny have the same end point and mid point
, mark | |
| 2848 // them as parallel | |
| 2849 void SkOpSegment::checkTiny() { | |
| 2850 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; | |
| 2851 SkOpSpan* thisSpan = fTs.begin() - 1; | |
| 2852 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny | |
| 2853 while (++thisSpan < endSpan) { | |
| 2854 if (!thisSpan->fTiny) { | |
| 2855 continue; | |
| 2856 } | |
| 2857 SkOpSpan* nextSpan = thisSpan + 1; | |
| 2858 double thisT = thisSpan->fT; | |
| 2859 double nextT = nextSpan->fT; | |
| 2860 if (thisT == nextT) { | |
| 2861 continue; | |
| 2862 } | |
| 2863 SkASSERT(thisT < nextT); | |
| 2864 SkASSERT(thisSpan->fPt == nextSpan->fPt); | |
| 2865 SkOpSegment* thisOther = thisSpan->fOther; | |
| 2866 SkOpSegment* nextOther = nextSpan->fOther; | |
| 2867 int oIndex = thisSpan->fOtherIndex; | |
| 2868 for (int oStep = -1; oStep <= 1; oStep += 2) { | |
| 2869 int oEnd = thisOther->nextExactSpan(oIndex, oStep); | |
| 2870 if (oEnd < 0) { | |
| 2871 continue; | |
| 2872 } | |
| 2873 const SkOpSpan& oSpan = thisOther->span(oEnd); | |
| 2874 int nIndex = nextSpan->fOtherIndex; | |
| 2875 for (int nStep = -1; nStep <= 1; nStep += 2) { | |
| 2876 int nEnd = nextOther->nextExactSpan(nIndex, nStep); | |
| 2877 if (nEnd < 0) { | |
| 2878 continue; | |
| 2879 } | |
| 2880 const SkOpSpan& nSpan = nextOther->span(nEnd); | |
| 2881 if (oSpan.fPt != nSpan.fPt) { | |
| 2882 continue; | |
| 2883 } | |
| 2884 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2; | |
| 2885 const SkPoint& oPt = thisOther->ptAtT(oMidT); | |
| 2886 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2; | |
| 2887 const SkPoint& nPt = nextOther->ptAtT(nMidT); | |
| 2888 if (!AlmostEqualUlps(oPt, nPt)) { | |
| 2889 continue; | |
| 2890 } | |
| 2891 #if DEBUG_CHECK_TINY | |
| 2892 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fI
D, | |
| 2893 thisOther->fID, nextOther->fID); | |
| 2894 #endif | |
| 2895 // this segment is missing a entry that the other contains | |
| 2896 // remember so we can add the missing one and recompute the indi
ces | |
| 2897 MissingSpan& missing = missingSpans.push_back(); | |
| 2898 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); | |
| 2899 missing.fSegment = thisOther; | |
| 2900 missing.fT = thisSpan->fOtherT; | |
| 2901 SkASSERT(this != nextOther); | |
| 2902 missing.fOther = nextOther; | |
| 2903 missing.fOtherT = nextSpan->fOtherT; | |
| 2904 missing.fPt = thisSpan->fPt; | |
| 2905 } | |
| 2906 } | |
| 2907 } | |
| 2908 int missingCount = missingSpans.count(); | |
| 2909 if (!missingCount) { | |
| 2910 return; | |
| 2911 } | |
| 2912 for (int index = 0; index < missingCount; ++index) { | |
| 2913 MissingSpan& missing = missingSpans[index]; | |
| 2914 if (missing.fSegment != missing.fOther) { | |
| 2915 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOthe
rT, false, | |
| 2916 missing.fPt); | |
| 2917 } | |
| 2918 } | |
| 2919 // OPTIMIZE: consolidate to avoid multiple calls to fix index | |
| 2920 for (int index = 0; index < missingCount; ++index) { | |
| 2921 MissingSpan& missing = missingSpans[index]; | |
| 2922 missing.fSegment->fixOtherTIndex(); | |
| 2923 missing.fOther->fixOtherTIndex(); | |
| 2924 } | |
| 2925 } | |
| 2926 | |
| 2927 bool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment
* other) const { | |
| 2928 int count = this->count(); | |
| 2929 for (int index = 0; index < count; ++index) { | |
| 2930 const SkOpSpan& span = this->span(index); | |
| 2931 if (span.fOther != other) { | |
| 2932 continue; | |
| 2933 } | |
| 2934 if (span.fPt == pt) { | |
| 2935 continue; | |
| 2936 } | |
| 2937 if (!AlmostEqualUlps(span.fPt, pt)) { | |
| 2938 continue; | |
| 2939 } | |
| 2940 if (fVerb != SkPath::kCubic_Verb) { | |
| 2941 return true; | |
| 2942 } | |
| 2943 double tInterval = t - span.fT; | |
| 2944 double tMid = t - tInterval / 2; | |
| 2945 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); | |
| 2946 return midPt.approximatelyEqual(xyAtT(t)); | |
| 2947 } | |
| 2948 return false; | |
| 2949 } | |
| 2950 | |
| 2951 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* o
ther, int oStart, | |
| 2952 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) cons
t { | |
| 2953 SkASSERT(span->fT == 0 || span->fT == 1); | |
| 2954 SkASSERT(span->fOtherT == 0 || span->fOtherT == 1); | |
| 2955 const SkOpSpan* otherSpan = &other->span(oEnd); | |
| 2956 double refT = otherSpan->fT; | |
| 2957 const SkPoint& refPt = otherSpan->fPt; | |
| 2958 const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0); | |
| 2959 do { | |
| 2960 const SkOpSegment* match = span->fOther; | |
| 2961 if (match == otherSpan->fOther) { | |
| 2962 // find start of respective spans and see if both have winding | |
| 2963 int startIndex, endIndex; | |
| 2964 if (span->fOtherT == 1) { | |
| 2965 endIndex = span->fOtherIndex; | |
| 2966 startIndex = match->nextExactSpan(endIndex, -1); | |
| 2967 } else { | |
| 2968 startIndex = span->fOtherIndex; | |
| 2969 endIndex = match->nextExactSpan(startIndex, 1); | |
| 2970 } | |
| 2971 const SkOpSpan& startSpan = match->span(startIndex); | |
| 2972 if (startSpan.fWindValue != 0) { | |
| 2973 // draw ray from endSpan.fPt perpendicular to end tangent and me
asure distance | |
| 2974 // to other segment. | |
| 2975 const SkOpSpan& endSpan = match->span(endIndex); | |
| 2976 SkDLine ray; | |
| 2977 SkVector dxdy; | |
| 2978 if (span->fOtherT == 1) { | |
| 2979 ray.fPts[0].set(startSpan.fPt); | |
| 2980 dxdy = match->dxdy(startIndex); | |
| 2981 } else { | |
| 2982 ray.fPts[0].set(endSpan.fPt); | |
| 2983 dxdy = match->dxdy(endIndex); | |
| 2984 } | |
| 2985 ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY; | |
| 2986 ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX; | |
| 2987 SkIntersections i; | |
| 2988 int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(
other->pts(), ray); | |
| 2989 for (int index = 0; index < roots; ++index) { | |
| 2990 if (ray.fPts[0].approximatelyEqual(i.pt(index))) { | |
| 2991 double matchMidT = (match->span(startIndex).fT | |
| 2992 + match->span(endIndex).fT) / 2; | |
| 2993 SkPoint matchMidPt = match->ptAtT(matchMidT); | |
| 2994 double otherMidT = (i[0][index] + other->span(oStart).fT
) / 2; | |
| 2995 SkPoint otherMidPt = other->ptAtT(otherMidT); | |
| 2996 if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)
) { | |
| 2997 *startPt = startSpan.fPt; | |
| 2998 *endPt = endSpan.fPt; | |
| 2999 *endT = endSpan.fT; | |
| 3000 return true; | |
| 3001 } | |
| 3002 } | |
| 3003 } | |
| 3004 } | |
| 3005 return false; | |
| 3006 } | |
| 3007 if (otherSpan == lastSpan) { | |
| 3008 break; | |
| 3009 } | |
| 3010 otherSpan += step; | |
| 3011 } while (otherSpan->fT == refT || otherSpan->fPt == refPt); | |
| 3012 return false; | |
| 3013 } | |
| 3014 | |
| 3015 int SkOpSegment::findEndSpan(int endIndex) const { | |
| 3016 const SkOpSpan* span = &fTs[--endIndex]; | |
| 3017 const SkPoint& lastPt = span->fPt; | |
| 3018 double endT = span->fT; | |
| 3019 do { | |
| 3020 span = &fTs[--endIndex]; | |
| 3021 } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == end
T || span->fTiny)); | |
| 3022 return endIndex + 1; | |
| 3023 } | 783 } |
| 3024 | 784 |
| 3025 /* | 785 /* |
| 3026 The M and S variable name parts stand for the operators. | 786 The M and S variable name parts stand for the operators. |
| 3027 Mi stands for Minuend (see wiki subtraction, analogous to difference) | 787 Mi stands for Minuend (see wiki subtraction, analogous to difference) |
| 3028 Su stands for Subtrahend | 788 Su stands for Subtrahend |
| 3029 The Opp variable name part designates that the value is for the Opposite operat
or. | 789 The Opp variable name part designates that the value is for the Opposite operat
or. |
| 3030 Opposite values result from combining coincident spans. | 790 Opposite values result from combining coincident spans. |
| 3031 */ | 791 */ |
| 3032 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
, int* nextEnd, | 792 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa
se** nextStart, |
| 3033 bool* unsortable, SkPathOp op, const int xo
rMiMask, | 793 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in
t xorSuMask) { |
| 3034 const int xorSuMask) { | 794 SkOpSpanBase* start = *nextStart; |
| 3035 const int startIndex = *nextStart; | 795 SkOpSpanBase* end = *nextEnd; |
| 3036 const int endIndex = *nextEnd; | 796 SkASSERT(start != end); |
| 3037 SkASSERT(startIndex != endIndex); | 797 int step = start->step(end); |
| 3038 SkDEBUGCODE(const int count = fTs.count()); | 798 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStar
t |
| 3039 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); | 799 if (other) { |
| 3040 int step = SkSign32(endIndex - startIndex); | |
| 3041 *nextStart = startIndex; | |
| 3042 SkOpSegment* other = isSimple(nextStart, &step); | |
| 3043 if (other) | |
| 3044 { | |
| 3045 // mark the smaller of startIndex, endIndex done, and all adjacent | 800 // mark the smaller of startIndex, endIndex done, and all adjacent |
| 3046 // spans with the same T value (but not 'other' spans) | 801 // spans with the same T value (but not 'other' spans) |
| 3047 #if DEBUG_WINDING | 802 #if DEBUG_WINDING |
| 3048 SkDebugf("%s simple\n", __FUNCTION__); | 803 SkDebugf("%s simple\n", __FUNCTION__); |
| 3049 #endif | 804 #endif |
| 3050 int min = SkMin32(startIndex, endIndex); | 805 SkOpSpan* startSpan = start->starter(end); |
| 3051 if (fTs[min].fDone) { | 806 if (startSpan->done()) { |
| 3052 return NULL; | 807 return NULL; |
| 3053 } | 808 } |
| 3054 markDoneBinary(min); | 809 markDone(startSpan); |
| 3055 double startT = other->fTs[*nextStart].fT; | 810 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->pre
v(); |
| 3056 *nextEnd = *nextStart; | |
| 3057 do { | |
| 3058 *nextEnd += step; | |
| 3059 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | |
| 3060 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | |
| 3061 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { | |
| 3062 *unsortable = true; | |
| 3063 return NULL; | |
| 3064 } | |
| 3065 return other; | 811 return other; |
| 3066 } | 812 } |
| 3067 const int end = nextExactSpan(startIndex, step); | 813 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextSt
art)->prev(); |
| 3068 SkASSERT(end >= 0); | 814 SkASSERT(endNear == end); // is this ever not end? |
| 3069 SkASSERT(startIndex - endIndex != 0); | 815 SkASSERT(endNear); |
| 3070 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 816 SkASSERT(start != endNear); |
| 817 SkASSERT((start->t() < endNear->t()) ^ (step < 0)); |
| 3071 // more than one viable candidate -- measure angles to find best | 818 // more than one viable candidate -- measure angles to find best |
| 3072 | 819 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp); |
| 3073 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp); | |
| 3074 bool sortable = calcWinding != SK_NaN32; | 820 bool sortable = calcWinding != SK_NaN32; |
| 3075 if (!sortable) { | 821 if (!sortable) { |
| 3076 *unsortable = true; | 822 *unsortable = true; |
| 3077 markDoneBinary(SkMin32(startIndex, endIndex)); | 823 markDone(start->starter(end)); |
| 3078 return NULL; | 824 return NULL; |
| 3079 } | 825 } |
| 3080 SkOpAngle* angle = spanToAngle(end, startIndex); | 826 SkOpAngle* angle = this->spanToAngle(end, start); |
| 3081 if (angle->unorderable()) { | 827 if (angle->unorderable()) { |
| 3082 *unsortable = true; | 828 *unsortable = true; |
| 3083 markDoneBinary(SkMin32(startIndex, endIndex)); | 829 markDone(start->starter(end)); |
| 3084 return NULL; | 830 return NULL; |
| 3085 } | 831 } |
| 3086 #if DEBUG_SORT | 832 #if DEBUG_SORT |
| 3087 SkDebugf("%s\n", __FUNCTION__); | 833 SkDebugf("%s\n", __FUNCTION__); |
| 3088 angle->debugLoop(); | 834 angle->debugLoop(); |
| 3089 #endif | 835 #endif |
| 3090 int sumMiWinding = updateWinding(endIndex, startIndex); | 836 int sumMiWinding = updateWinding(end, start); |
| 3091 if (sumMiWinding == SK_MinS32) { | 837 if (sumMiWinding == SK_MinS32) { |
| 3092 *unsortable = true; | 838 *unsortable = true; |
| 3093 markDoneBinary(SkMin32(startIndex, endIndex)); | 839 markDone(start->starter(end)); |
| 3094 return NULL; | 840 return NULL; |
| 3095 } | 841 } |
| 3096 int sumSuWinding = updateOppWinding(endIndex, startIndex); | 842 int sumSuWinding = updateOppWinding(end, start); |
| 3097 if (operand()) { | 843 if (operand()) { |
| 3098 SkTSwap<int>(sumMiWinding, sumSuWinding); | 844 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 3099 } | 845 } |
| 3100 SkOpAngle* nextAngle = angle->next(); | 846 SkOpAngle* nextAngle = angle->next(); |
| 3101 const SkOpAngle* foundAngle = NULL; | 847 const SkOpAngle* foundAngle = NULL; |
| 3102 bool foundDone = false; | 848 bool foundDone = false; |
| 3103 // iterate through the angle, and compute everyone's winding | 849 // iterate through the angle, and compute everyone's winding |
| 3104 SkOpSegment* nextSegment; | 850 SkOpSegment* nextSegment; |
| 3105 int activeCount = 0; | 851 int activeCount = 0; |
| 3106 do { | 852 do { |
| 3107 nextSegment = nextAngle->segment(); | 853 nextSegment = nextAngle->segment(); |
| 3108 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle
->start(), | 854 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle
->start(), |
| 3109 nextAngle->end(), op, &sumMiWinding, &sumSuWinding); | 855 nextAngle->end(), op, &sumMiWinding, &sumSuWinding); |
| 3110 if (activeAngle) { | 856 if (activeAngle) { |
| 3111 ++activeCount; | 857 ++activeCount; |
| 3112 if (!foundAngle || (foundDone && activeCount & 1)) { | 858 if (!foundAngle || (foundDone && activeCount & 1)) { |
| 3113 if (nextSegment->isTiny(nextAngle)) { | |
| 3114 *unsortable = true; | |
| 3115 markDoneBinary(SkMin32(startIndex, endIndex)); | |
| 3116 return NULL; | |
| 3117 } | |
| 3118 foundAngle = nextAngle; | 859 foundAngle = nextAngle; |
| 3119 foundDone = nextSegment->done(nextAngle); | 860 foundDone = nextSegment->done(nextAngle); |
| 3120 } | 861 } |
| 3121 } | 862 } |
| 3122 if (nextSegment->done()) { | 863 if (nextSegment->done()) { |
| 3123 continue; | 864 continue; |
| 3124 } | 865 } |
| 3125 if (nextSegment->isTiny(nextAngle)) { | 866 if (!activeAngle) { |
| 3126 continue; | 867 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->
end()); |
| 3127 } | 868 } |
| 3128 if (!activeAngle) { | 869 SkOpSpanBase* last = nextAngle->lastMarked(); |
| 3129 (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextA
ngle->end()); | |
| 3130 } | |
| 3131 SkOpSpan* last = nextAngle->lastMarked(); | |
| 3132 if (last) { | 870 if (last) { |
| 3133 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); | 871 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); |
| 3134 *chase->append() = last; | 872 *chase->append() = last; |
| 3135 #if DEBUG_WINDING | 873 #if DEBUG_WINDING |
| 3136 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, | 874 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__, |
| 3137 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, | 875 last->segment()->debugID(), last->debugID()); |
| 3138 last->fSmall); | 876 if (!last->final()) { |
| 877 SkDebugf(" windSum=%d", last->upCast()->windSum()); |
| 878 } |
| 879 SkDebugf("\n"); |
| 3139 #endif | 880 #endif |
| 3140 } | 881 } |
| 3141 } while ((nextAngle = nextAngle->next()) != angle); | 882 } while ((nextAngle = nextAngle->next()) != angle); |
| 3142 #if DEBUG_ANGLE | 883 start->segment()->markDone(start->starter(end)); |
| 3143 if (foundAngle) { | |
| 3144 foundAngle->debugSameAs(foundAngle); | |
| 3145 } | |
| 3146 #endif | |
| 3147 | |
| 3148 markDoneBinary(SkMin32(startIndex, endIndex)); | |
| 3149 if (!foundAngle) { | 884 if (!foundAngle) { |
| 3150 return NULL; | 885 return NULL; |
| 3151 } | 886 } |
| 3152 *nextStart = foundAngle->start(); | 887 *nextStart = foundAngle->start(); |
| 3153 *nextEnd = foundAngle->end(); | 888 *nextEnd = foundAngle->end(); |
| 3154 nextSegment = foundAngle->segment(); | 889 nextSegment = foundAngle->segment(); |
| 3155 #if DEBUG_WINDING | 890 #if DEBUG_WINDING |
| 3156 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 891 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
| 3157 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 892 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
| 3158 #endif | 893 #endif |
| 3159 return nextSegment; | 894 return nextSegment; |
| 3160 } | 895 } |
| 3161 | 896 |
| 3162 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
Start, | 897 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase, |
| 3163 int* nextEnd, bool* unsortable) { | 898 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) { |
| 3164 const int startIndex = *nextStart; | 899 SkOpSpanBase* start = *nextStart; |
| 3165 const int endIndex = *nextEnd; | 900 SkOpSpanBase* end = *nextEnd; |
| 3166 SkASSERT(startIndex != endIndex); | 901 SkASSERT(start != end); |
| 3167 SkDEBUGCODE(const int count = fTs.count()); | 902 int step = start->step(end); |
| 3168 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); | 903 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStar
t |
| 3169 int step = SkSign32(endIndex - startIndex); | 904 if (other) { |
| 3170 *nextStart = startIndex; | |
| 3171 SkOpSegment* other = isSimple(nextStart, &step); | |
| 3172 if (other) | |
| 3173 { | |
| 3174 // mark the smaller of startIndex, endIndex done, and all adjacent | 905 // mark the smaller of startIndex, endIndex done, and all adjacent |
| 3175 // spans with the same T value (but not 'other' spans) | 906 // spans with the same T value (but not 'other' spans) |
| 3176 #if DEBUG_WINDING | 907 #if DEBUG_WINDING |
| 3177 SkDebugf("%s simple\n", __FUNCTION__); | 908 SkDebugf("%s simple\n", __FUNCTION__); |
| 3178 #endif | 909 #endif |
| 3179 int min = SkMin32(startIndex, endIndex); | 910 SkOpSpan* startSpan = start->starter(end); |
| 3180 if (fTs[min].fDone) { | 911 if (startSpan->done()) { |
| 3181 return NULL; | 912 return NULL; |
| 3182 } | 913 } |
| 3183 markDoneUnary(min); | 914 markDone(startSpan); |
| 3184 double startT = other->fTs[*nextStart].fT; | 915 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->pre
v(); |
| 3185 *nextEnd = *nextStart; | |
| 3186 do { | |
| 3187 *nextEnd += step; | |
| 3188 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | |
| 3189 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | |
| 3190 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { | |
| 3191 *unsortable = true; | |
| 3192 return NULL; | |
| 3193 } | |
| 3194 return other; | 916 return other; |
| 3195 } | 917 } |
| 3196 const int end = nextExactSpan(startIndex, step); | 918 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextSt
art)->prev(); |
| 3197 SkASSERT(end >= 0); | 919 SkASSERT(endNear == end); // is this ever not end? |
| 3198 SkASSERT(startIndex - endIndex != 0); | 920 SkASSERT(endNear); |
| 3199 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 921 SkASSERT(start != endNear); |
| 922 SkASSERT((start->t() < endNear->t()) ^ (step < 0)); |
| 3200 // more than one viable candidate -- measure angles to find best | 923 // more than one viable candidate -- measure angles to find best |
| 3201 | 924 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding); |
| 3202 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding); | |
| 3203 bool sortable = calcWinding != SK_NaN32; | 925 bool sortable = calcWinding != SK_NaN32; |
| 3204 if (!sortable) { | 926 if (!sortable) { |
| 3205 *unsortable = true; | 927 *unsortable = true; |
| 3206 markDoneUnary(SkMin32(startIndex, endIndex)); | 928 markDone(start->starter(end)); |
| 3207 return NULL; | 929 return NULL; |
| 3208 } | 930 } |
| 3209 SkOpAngle* angle = spanToAngle(end, startIndex); | 931 SkOpAngle* angle = this->spanToAngle(end, start); |
| 932 if (angle->unorderable()) { |
| 933 *unsortable = true; |
| 934 markDone(start->starter(end)); |
| 935 return NULL; |
| 936 } |
| 3210 #if DEBUG_SORT | 937 #if DEBUG_SORT |
| 3211 SkDebugf("%s\n", __FUNCTION__); | 938 SkDebugf("%s\n", __FUNCTION__); |
| 3212 angle->debugLoop(); | 939 angle->debugLoop(); |
| 3213 #endif | 940 #endif |
| 3214 int sumWinding = updateWinding(endIndex, startIndex); | 941 int sumWinding = updateWinding(end, start); |
| 3215 SkOpAngle* nextAngle = angle->next(); | 942 SkOpAngle* nextAngle = angle->next(); |
| 3216 const SkOpAngle* foundAngle = NULL; | 943 const SkOpAngle* foundAngle = NULL; |
| 3217 bool foundDone = false; | 944 bool foundDone = false; |
| 945 // iterate through the angle, and compute everyone's winding |
| 3218 SkOpSegment* nextSegment; | 946 SkOpSegment* nextSegment; |
| 3219 int activeCount = 0; | 947 int activeCount = 0; |
| 3220 do { | 948 do { |
| 3221 nextSegment = nextAngle->segment(); | 949 nextSegment = nextAngle->segment(); |
| 3222 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn
gle->end(), | 950 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn
gle->end(), |
| 3223 &sumWinding); | 951 &sumWinding); |
| 3224 if (activeAngle) { | 952 if (activeAngle) { |
| 3225 ++activeCount; | 953 ++activeCount; |
| 3226 if (!foundAngle || (foundDone && activeCount & 1)) { | 954 if (!foundAngle || (foundDone && activeCount & 1)) { |
| 3227 if (nextSegment->isTiny(nextAngle)) { | |
| 3228 *unsortable = true; | |
| 3229 markDoneUnary(SkMin32(startIndex, endIndex)); | |
| 3230 return NULL; | |
| 3231 } | |
| 3232 foundAngle = nextAngle; | 955 foundAngle = nextAngle; |
| 3233 foundDone = nextSegment->done(nextAngle); | 956 foundDone = nextSegment->done(nextAngle); |
| 3234 } | 957 } |
| 3235 } | 958 } |
| 3236 if (nextSegment->done()) { | 959 if (nextSegment->done()) { |
| 3237 continue; | 960 continue; |
| 3238 } | 961 } |
| 3239 if (nextSegment->isTiny(nextAngle)) { | 962 if (!activeAngle) { |
| 3240 continue; | 963 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->
end()); |
| 3241 } | 964 } |
| 3242 if (!activeAngle) { | 965 SkOpSpanBase* last = nextAngle->lastMarked(); |
| 3243 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->en
d()); | |
| 3244 } | |
| 3245 SkOpSpan* last = nextAngle->lastMarked(); | |
| 3246 if (last) { | 966 if (last) { |
| 3247 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); | 967 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); |
| 3248 *chase->append() = last; | 968 *chase->append() = last; |
| 3249 #if DEBUG_WINDING | 969 #if DEBUG_WINDING |
| 3250 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, | 970 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__, |
| 3251 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, | 971 last->segment()->debugID(), last->debugID()); |
| 3252 last->fSmall); | 972 if (!last->final()) { |
| 973 SkDebugf(" windSum=%d", last->upCast()->windSum()); |
| 974 } |
| 975 SkDebugf("\n"); |
| 3253 #endif | 976 #endif |
| 3254 } | 977 } |
| 3255 } while ((nextAngle = nextAngle->next()) != angle); | 978 } while ((nextAngle = nextAngle->next()) != angle); |
| 3256 markDoneUnary(SkMin32(startIndex, endIndex)); | 979 start->segment()->markDone(start->starter(end)); |
| 3257 if (!foundAngle) { | 980 if (!foundAngle) { |
| 3258 return NULL; | 981 return NULL; |
| 3259 } | 982 } |
| 3260 *nextStart = foundAngle->start(); | 983 *nextStart = foundAngle->start(); |
| 3261 *nextEnd = foundAngle->end(); | 984 *nextEnd = foundAngle->end(); |
| 3262 nextSegment = foundAngle->segment(); | 985 nextSegment = foundAngle->segment(); |
| 3263 #if DEBUG_WINDING | 986 #if DEBUG_WINDING |
| 3264 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 987 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
| 3265 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 988 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
| 3266 #endif | 989 #endif |
| 3267 return nextSegment; | 990 return nextSegment; |
| 3268 } | 991 } |
| 3269 | 992 |
| 3270 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
able) { | 993 SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** n
extEnd, |
| 3271 const int startIndex = *nextStart; | 994 bool* unsortable) { |
| 3272 const int endIndex = *nextEnd; | 995 SkOpSpanBase* start = *nextStart; |
| 3273 SkASSERT(startIndex != endIndex); | 996 SkOpSpanBase* end = *nextEnd; |
| 3274 SkDEBUGCODE(int count = fTs.count()); | 997 SkASSERT(start != end); |
| 3275 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); | 998 int step = start->step(end); |
| 3276 int step = SkSign32(endIndex - startIndex); | 999 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStar
t |
| 3277 // Detect cases where all the ends canceled out (e.g., | 1000 if (other) { |
| 3278 // there is no angle) and therefore there's only one valid connection | 1001 // mark the smaller of startIndex, endIndex done, and all adjacent |
| 3279 *nextStart = startIndex; | 1002 // spans with the same T value (but not 'other' spans) |
| 3280 SkOpSegment* other = isSimple(nextStart, &step); | |
| 3281 if (other) | |
| 3282 { | |
| 3283 #if DEBUG_WINDING | 1003 #if DEBUG_WINDING |
| 3284 SkDebugf("%s simple\n", __FUNCTION__); | 1004 SkDebugf("%s simple\n", __FUNCTION__); |
| 3285 #endif | 1005 #endif |
| 3286 int min = SkMin32(startIndex, endIndex); | 1006 SkOpSpan* startSpan = start->starter(end); |
| 3287 if (fTs[min].fDone) { | 1007 if (startSpan->done()) { |
| 3288 return NULL; | 1008 return NULL; |
| 3289 } | 1009 } |
| 3290 markDone(min, 1); | 1010 markDone(startSpan); |
| 3291 double startT = other->fTs[*nextStart].fT; | 1011 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->pre
v(); |
| 3292 // FIXME: I don't know why the logic here is difference from the winding
case | |
| 3293 SkDEBUGCODE(bool firstLoop = true;) | |
| 3294 if ((approximately_less_than_zero(startT) && step < 0) | |
| 3295 || (approximately_greater_than_one(startT) && step > 0)) { | |
| 3296 step = -step; | |
| 3297 SkDEBUGCODE(firstLoop = false;) | |
| 3298 } | |
| 3299 do { | |
| 3300 *nextEnd = *nextStart; | |
| 3301 do { | |
| 3302 *nextEnd += step; | |
| 3303 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | |
| 3304 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) { | |
| 3305 break; | |
| 3306 } | |
| 3307 SkASSERT(firstLoop); | |
| 3308 SkDEBUGCODE(firstLoop = false;) | |
| 3309 step = -step; | |
| 3310 } while (true); | |
| 3311 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | |
| 3312 return other; | 1012 return other; |
| 3313 } | 1013 } |
| 3314 SkASSERT(startIndex - endIndex != 0); | 1014 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next(
) \ |
| 3315 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1015 : (*nextStart)->prev()); |
| 3316 // parallel block above with presorted version | 1016 SkASSERT(endNear == end); // is this ever not end? |
| 3317 int end = nextExactSpan(startIndex, step); | 1017 SkASSERT(endNear); |
| 3318 SkASSERT(end >= 0); | 1018 SkASSERT(start != endNear); |
| 3319 SkOpAngle* angle = spanToAngle(end, startIndex); | 1019 SkASSERT((start->t() < endNear->t()) ^ (step < 0)); |
| 3320 SkASSERT(angle); | 1020 SkOpAngle* angle = this->spanToAngle(end, start); |
| 1021 if (angle->unorderable()) { |
| 1022 *unsortable = true; |
| 1023 markDone(start->starter(end)); |
| 1024 return NULL; |
| 1025 } |
| 3321 #if DEBUG_SORT | 1026 #if DEBUG_SORT |
| 3322 SkDebugf("%s\n", __FUNCTION__); | 1027 SkDebugf("%s\n", __FUNCTION__); |
| 3323 angle->debugLoop(); | 1028 angle->debugLoop(); |
| 3324 #endif | 1029 #endif |
| 3325 SkOpAngle* nextAngle = angle->next(); | 1030 SkOpAngle* nextAngle = angle->next(); |
| 3326 const SkOpAngle* foundAngle = NULL; | 1031 const SkOpAngle* foundAngle = NULL; |
| 3327 bool foundDone = false; | 1032 bool foundDone = false; |
| 1033 // iterate through the angle, and compute everyone's winding |
| 3328 SkOpSegment* nextSegment; | 1034 SkOpSegment* nextSegment; |
| 3329 int activeCount = 0; | 1035 int activeCount = 0; |
| 3330 do { | 1036 do { |
| 3331 nextSegment = nextAngle->segment(); | 1037 nextSegment = nextAngle->segment(); |
| 3332 ++activeCount; | 1038 ++activeCount; |
| 3333 if (!foundAngle || (foundDone && activeCount & 1)) { | 1039 if (!foundAngle || (foundDone && activeCount & 1)) { |
| 3334 if (nextSegment->isTiny(nextAngle)) { | |
| 3335 *unsortable = true; | |
| 3336 return NULL; | |
| 3337 } | |
| 3338 foundAngle = nextAngle; | 1040 foundAngle = nextAngle; |
| 3339 if (!(foundDone = nextSegment->done(nextAngle))) { | 1041 if (!(foundDone = nextSegment->done(nextAngle))) { |
| 3340 break; | 1042 break; |
| 3341 } | 1043 } |
| 3342 } | 1044 } |
| 3343 nextAngle = nextAngle->next(); | 1045 nextAngle = nextAngle->next(); |
| 3344 } while (nextAngle != angle); | 1046 } while (nextAngle != angle); |
| 3345 markDone(SkMin32(startIndex, endIndex), 1); | 1047 start->segment()->markDone(start->starter(end)); |
| 3346 if (!foundAngle) { | 1048 if (!foundAngle) { |
| 3347 return NULL; | 1049 return NULL; |
| 3348 } | 1050 } |
| 3349 *nextStart = foundAngle->start(); | 1051 *nextStart = foundAngle->start(); |
| 3350 *nextEnd = foundAngle->end(); | 1052 *nextEnd = foundAngle->end(); |
| 3351 nextSegment = foundAngle->segment(); | 1053 nextSegment = foundAngle->segment(); |
| 3352 #if DEBUG_WINDING | 1054 #if DEBUG_WINDING |
| 3353 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 1055 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
| 3354 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 1056 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
| 3355 #endif | 1057 #endif |
| 3356 return nextSegment; | 1058 return nextSegment; |
| 3357 } | 1059 } |
| 3358 | 1060 |
| 3359 int SkOpSegment::findStartSpan(int startIndex) const { | 1061 SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS
panBase** endPtr, |
| 3360 int index = startIndex; | 1062 bool* unsortable, SkChunkAlloc* allocator) { |
| 3361 const SkOpSpan* span = &fTs[index]; | |
| 3362 const SkPoint& firstPt = span->fPt; | |
| 3363 double firstT = span->fT; | |
| 3364 const SkOpSpan* prior; | |
| 3365 do { | |
| 3366 prior = span; | |
| 3367 span = &fTs[++index]; | |
| 3368 } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt) | |
| 3369 && (span->fT == firstT || prior->fTiny)); | |
| 3370 return index; | |
| 3371 } | |
| 3372 | |
| 3373 int SkOpSegment::findExactT(double t, const SkOpSegment* match) const { | |
| 3374 int count = this->count(); | |
| 3375 for (int index = 0; index < count; ++index) { | |
| 3376 const SkOpSpan& span = fTs[index]; | |
| 3377 if (span.fT == t && span.fOther == match) { | |
| 3378 return index; | |
| 3379 } | |
| 3380 } | |
| 3381 SkASSERT(0); | |
| 3382 return -1; | |
| 3383 } | |
| 3384 | |
| 3385 | |
| 3386 | |
| 3387 int SkOpSegment::findOtherT(double t, const SkOpSegment* match) const { | |
| 3388 int count = this->count(); | |
| 3389 for (int index = 0; index < count; ++index) { | |
| 3390 const SkOpSpan& span = fTs[index]; | |
| 3391 if (span.fOtherT == t && span.fOther == match) { | |
| 3392 return index; | |
| 3393 } | |
| 3394 } | |
| 3395 return -1; | |
| 3396 } | |
| 3397 | |
| 3398 int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) co
nst { | |
| 3399 int count = this->count(); | |
| 3400 // prefer exact matches over approximate matches | |
| 3401 for (int index = 0; index < count; ++index) { | |
| 3402 const SkOpSpan& span = fTs[index]; | |
| 3403 if (span.fT == t && span.fOther == match) { | |
| 3404 return index; | |
| 3405 } | |
| 3406 } | |
| 3407 for (int index = 0; index < count; ++index) { | |
| 3408 const SkOpSpan& span = fTs[index]; | |
| 3409 if (approximately_equal_orderable(span.fT, t) && span.fOther == match) { | |
| 3410 return index; | |
| 3411 } | |
| 3412 } | |
| 3413 // Usually, the pair of ts are an exact match. It's possible that the t valu
es have | |
| 3414 // been adjusted to make multiple intersections align. In this rare case, lo
ok for a | |
| 3415 // matching point / match pair instead. | |
| 3416 for (int index = 0; index < count; ++index) { | |
| 3417 const SkOpSpan& span = fTs[index]; | |
| 3418 if (span.fPt == pt && span.fOther == match) { | |
| 3419 return index; | |
| 3420 } | |
| 3421 } | |
| 3422 SkASSERT(0); | |
| 3423 return -1; | |
| 3424 } | |
| 3425 | |
| 3426 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
able, | |
| 3427 bool firstPass) { | |
| 3428 // iterate through T intersections and return topmost | 1063 // iterate through T intersections and return topmost |
| 3429 // topmost tangent from y-min to first pt is closer to horizontal | 1064 // topmost tangent from y-min to first pt is closer to horizontal |
| 3430 SkASSERT(!done()); | 1065 SkASSERT(!done()); |
| 3431 int firstT = -1; | 1066 SkOpSpanBase* firstT = NULL; |
| 3432 /* SkPoint topPt = */ activeLeftTop(&firstT); | 1067 (void) this->activeLeftTop(&firstT); |
| 3433 if (firstT < 0) { | 1068 if (!firstT) { |
| 3434 *unsortable = !firstPass; | 1069 *unsortable = !firstPass; |
| 3435 firstT = 0; | 1070 firstT = &fHead; |
| 3436 while (fTs[firstT].fDone) { | 1071 while (firstT->upCast()->done()) { |
| 3437 SkASSERT(firstT < fTs.count()); | 1072 firstT = firstT->upCast()->next(); |
| 3438 ++firstT; | |
| 3439 } | 1073 } |
| 3440 *tIndexPtr = firstT; | 1074 *startPtr = firstT; |
| 3441 *endIndexPtr = nextExactSpan(firstT, 1); | 1075 *endPtr = firstT->upCast()->next(); |
| 3442 return this; | 1076 return this; |
| 3443 } | 1077 } |
| 3444 // sort the edges to find the leftmost | 1078 // sort the edges to find the leftmost |
| 3445 int step = 1; | 1079 int step = 1; |
| 3446 int end; | 1080 SkOpSpanBase* end; |
| 3447 if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) { | 1081 if (firstT->final() || firstT->upCast()->done()) { |
| 3448 step = -1; | 1082 step = -1; |
| 3449 end = nextSpan(firstT, step); | 1083 end = firstT->prev(); |
| 3450 SkASSERT(end != -1); | 1084 SkASSERT(end); |
| 1085 } else { |
| 1086 end = firstT->upCast()->next(); |
| 3451 } | 1087 } |
| 3452 // if the topmost T is not on end, or is three-way or more, find left | 1088 // if the topmost T is not on end, or is three-way or more, find left |
| 3453 // look for left-ness from tLeft to firstT (matching y of other) | 1089 // look for left-ness from tLeft to firstT (matching y of other) |
| 3454 SkASSERT(firstT - end != 0); | 1090 SkASSERT(firstT != end); |
| 3455 SkOpAngle* markAngle = spanToAngle(firstT, end); | 1091 SkOpAngle* markAngle = spanToAngle(firstT, end); |
| 3456 if (!markAngle) { | 1092 if (!markAngle) { |
| 3457 markAngle = addSingletonAngles(step); | 1093 markAngle = addSingletonAngles(step, allocator); |
| 3458 } | 1094 } |
| 3459 markAngle->markStops(); | 1095 markAngle->markStops(); |
| 3460 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical()
? markAngle | 1096 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical()
? markAngle |
| 3461 : markAngle->findFirst(); | 1097 : markAngle->findFirst(); |
| 3462 if (!baseAngle) { | 1098 if (!baseAngle) { |
| 3463 return NULL; // nothing to do | 1099 return NULL; // nothing to do |
| 3464 } | 1100 } |
| 3465 SkScalar top = SK_ScalarMax; | 1101 SkScalar top = SK_ScalarMax; |
| 3466 const SkOpAngle* firstAngle = NULL; | 1102 const SkOpAngle* firstAngle = NULL; |
| 3467 const SkOpAngle* angle = baseAngle; | 1103 const SkOpAngle* angle = baseAngle; |
| 3468 do { | 1104 do { |
| 3469 if (!angle->unorderable()) { | 1105 if (!angle->unorderable()) { |
| 3470 SkOpSegment* next = angle->segment(); | 1106 const SkOpSegment* next = angle->segment(); |
| 3471 SkPathOpsBounds bounds; | 1107 SkPathOpsBounds bounds; |
| 3472 next->subDivideBounds(angle->end(), angle->start(), &bounds); | 1108 next->subDivideBounds(angle->end(), angle->start(), &bounds); |
| 3473 bool nearSame = AlmostEqualUlps(top, bounds.top()); | 1109 bool nearSame = AlmostEqualUlps(top, bounds.top()); |
| 3474 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->s
ectorStart(); | 1110 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->s
ectorStart(); |
| 3475 bool lesserSector = top > bounds.fTop; | 1111 bool lesserSector = top > bounds.fTop; |
| 3476 if (lesserSector && (!nearSame || lowerSector)) { | 1112 if (lesserSector && (!nearSame || lowerSector)) { |
| 3477 top = bounds.fTop; | 1113 top = bounds.fTop; |
| 3478 firstAngle = angle; | 1114 firstAngle = angle; |
| 3479 } | 1115 } |
| 3480 } | 1116 } |
| 3481 angle = angle->next(); | 1117 angle = angle->next(); |
| 3482 } while (angle != baseAngle); | 1118 } while (angle != baseAngle); |
| 3483 if (!firstAngle) { | 1119 if (!firstAngle) { |
| 3484 return NULL; // if all are unorderable, give up | 1120 return NULL; // if all are unorderable, give up |
| 3485 } | 1121 } |
| 3486 #if DEBUG_SORT | 1122 #if DEBUG_SORT |
| 3487 SkDebugf("%s\n", __FUNCTION__); | 1123 SkDebugf("%s\n", __FUNCTION__); |
| 3488 firstAngle->debugLoop(); | 1124 firstAngle->debugLoop(); |
| 3489 #endif | 1125 #endif |
| 3490 // skip edges that have already been processed | 1126 // skip edges that have already been processed |
| 3491 angle = firstAngle; | 1127 angle = firstAngle; |
| 3492 SkOpSegment* leftSegment = NULL; | 1128 SkOpSegment* leftSegment = NULL; |
| 3493 bool looped = false; | 1129 bool looped = false; |
| 3494 do { | 1130 do { |
| 3495 *unsortable = angle->unorderable(); | 1131 *unsortable = angle->unorderable(); |
| 3496 if (firstPass || !*unsortable) { | 1132 if (firstPass || !*unsortable) { |
| 3497 leftSegment = angle->segment(); | 1133 leftSegment = angle->segment(); |
| 3498 *tIndexPtr = angle->end(); | 1134 *startPtr = angle->end(); |
| 3499 *endIndexPtr = angle->start(); | 1135 *endPtr = angle->start(); |
| 3500 if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) { | 1136 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr); |
| 1137 if (!firstSpan->done()) { |
| 3501 break; | 1138 break; |
| 3502 } | 1139 } |
| 3503 } | 1140 } |
| 3504 angle = angle->next(); | 1141 angle = angle->next(); |
| 3505 looped = true; | 1142 looped = true; |
| 3506 } while (angle != firstAngle); | 1143 } while (angle != firstAngle); |
| 3507 if (angle == firstAngle && looped) { | 1144 if (angle == firstAngle && looped) { |
| 3508 return NULL; | 1145 return NULL; |
| 3509 } | 1146 } |
| 3510 if (leftSegment->verb() >= SkPath::kQuad_Verb) { | 1147 if (leftSegment->verb() >= SkPath::kQuad_Verb) { |
| 3511 const int tIndex = *tIndexPtr; | 1148 SkOpSpanBase* start = *startPtr; |
| 3512 const int endIndex = *endIndexPtr; | 1149 SkOpSpanBase* end = *endPtr; |
| 3513 bool swap; | 1150 bool swap; |
| 3514 if (!leftSegment->clockwise(tIndex, endIndex, &swap)) { | 1151 if (!leftSegment->clockwise(start, end, &swap)) { |
| 3515 #if DEBUG_SWAP_TOP | 1152 #if DEBUG_SWAP_TOP |
| 3516 SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%
d monotonic=%d\n", | 1153 SkDebugf("%s swap=%d inflections=%d monotonic=%d\n", |
| 3517 __FUNCTION__, | 1154 __FUNCTION__, |
| 3518 swap, leftSegment->debugInflections(tIndex, endIndex), | 1155 swap, leftSegment->debugInflections(start, end), |
| 3519 leftSegment->serpentine(tIndex, endIndex), | 1156 leftSegment->monotonicInY(start, end)); |
| 3520 leftSegment->controlsContainedByEnds(tIndex, endIndex), | |
| 3521 leftSegment->monotonicInY(tIndex, endIndex)); | |
| 3522 #endif | 1157 #endif |
| 3523 if (swap) { | 1158 if (swap) { |
| 3524 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first | 1159 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first |
| 3525 // sorted but merely the first not already processed (i.e., not done) | 1160 // sorted but merely the first not already processed (i.e., not done) |
| 3526 SkTSwap(*tIndexPtr, *endIndexPtr); | 1161 SkTSwap(*startPtr, *endPtr); |
| 3527 } | 1162 } |
| 3528 } | 1163 } |
| 3529 } | 1164 } |
| 3530 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny); | |
| 3531 return leftSegment; | 1165 return leftSegment; |
| 3532 } | 1166 } |
| 3533 | 1167 |
| 3534 int SkOpSegment::firstActive(int tIndex) const { | 1168 SkOpGlobalState* SkOpSegment::globalState() const { |
| 3535 while (fTs[tIndex].fTiny) { | 1169 return contour()->globalState(); |
| 3536 SkASSERT(!isCanceled(tIndex)); | |
| 3537 ++tIndex; | |
| 3538 } | |
| 3539 return tIndex; | |
| 3540 } | 1170 } |
| 3541 | 1171 |
| 3542 // FIXME: not crazy about this | 1172 void SkOpSegment::init(SkPoint pts[], SkOpContour* contour, SkPath::Verb verb) { |
| 3543 // when the intersections are performed, the other index is into an | 1173 fContour = contour; |
| 3544 // incomplete array. As the array grows, the indices become incorrect | 1174 fNext = NULL; |
| 3545 // while the following fixes the indices up again, it isn't smart about | 1175 fPts = pts; |
| 3546 // skipping segments whose indices are already correct | 1176 fVerb = verb; |
| 3547 // assuming we leave the code that wrote the index in the first place | 1177 fCount = 0; |
| 3548 // FIXME: if called after remove, this needs to correct tiny | 1178 fDoneCount = 0; |
| 3549 void SkOpSegment::fixOtherTIndex() { | 1179 fVisited = false; |
| 3550 int iCount = fTs.count(); | 1180 SkOpSpan* zeroSpan = &fHead; |
| 3551 for (int i = 0; i < iCount; ++i) { | 1181 zeroSpan->init(this, NULL, 0, fPts[0]); |
| 3552 SkOpSpan& iSpan = fTs[i]; | 1182 SkOpSpanBase* oneSpan = &fTail; |
| 3553 double oT = iSpan.fOtherT; | 1183 zeroSpan->setNext(oneSpan); |
| 3554 SkOpSegment* other = iSpan.fOther; | 1184 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
| 3555 int oCount = other->fTs.count(); | 1185 PATH_OPS_DEBUG_CODE(fID = globalState()->nextSegmentID()); |
| 3556 SkDEBUGCODE(iSpan.fOtherIndex = -1); | |
| 3557 for (int o = 0; o < oCount; ++o) { | |
| 3558 SkOpSpan& oSpan = other->fTs[o]; | |
| 3559 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan
.fT) { | |
| 3560 iSpan.fOtherIndex = o; | |
| 3561 oSpan.fOtherIndex = i; | |
| 3562 break; | |
| 3563 } | |
| 3564 } | |
| 3565 SkASSERT(iSpan.fOtherIndex >= 0); | |
| 3566 } | |
| 3567 } | 1186 } |
| 3568 | 1187 |
| 3569 bool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const { | 1188 void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, |
| 3570 int foundEnds = 0; | 1189 SkOpAngle::IncludeType angleIncludeType) { |
| 3571 int count = this->count(); | 1190 int local = SkOpSegment::SpanSign(start, end); |
| 3572 for (int index = 0; index < count; ++index) { | |
| 3573 const SkOpSpan& span = this->span(index); | |
| 3574 if (span.fCoincident) { | |
| 3575 foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.f
T)); | |
| 3576 } | |
| 3577 } | |
| 3578 SkASSERT(foundEnds != 7); | |
| 3579 return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6; // two bit
s set | |
| 3580 } | |
| 3581 | |
| 3582 bool SkOpSegment::inconsistentAngle(int maxWinding, int sumWinding, int oppMaxWi
nding, | |
| 3583 int oppSumWinding, const SkOpAngle* angle) const { | |
| 3584 SkASSERT(angle->segment() == this); | |
| 3585 if (UseInnerWinding(maxWinding, sumWinding)) { | |
| 3586 maxWinding = sumWinding; | |
| 3587 } | |
| 3588 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { | |
| 3589 oppMaxWinding = oppSumWinding; | |
| 3590 } | |
| 3591 return inconsistentWinding(angle, maxWinding, oppMaxWinding); | |
| 3592 } | |
| 3593 | |
| 3594 bool SkOpSegment::inconsistentWinding(const SkOpAngle* angle, int winding, | |
| 3595 int oppWinding) const { | |
| 3596 int index = angle->start(); | |
| 3597 int endIndex = angle->end(); | |
| 3598 int min = SkMin32(index, endIndex); | |
| 3599 int step = SkSign32(endIndex - index); | |
| 3600 if (inconsistentWinding(min, winding, oppWinding)) { | |
| 3601 return true; | |
| 3602 } | |
| 3603 const SkOpSegment* other = this; | |
| 3604 while ((other = other->nextChase(&index, &step, &min, NULL))) { | |
| 3605 if (other->fTs[min].fWindSum != SK_MinS32) { | |
| 3606 break; | |
| 3607 } | |
| 3608 if (fOperand == other->fOperand) { | |
| 3609 if (other->inconsistentWinding(min, winding, oppWinding)) { | |
| 3610 return true; | |
| 3611 } | |
| 3612 } else { | |
| 3613 if (other->inconsistentWinding(min, oppWinding, winding)) { | |
| 3614 return true; | |
| 3615 } | |
| 3616 } | |
| 3617 } | |
| 3618 return false; | |
| 3619 } | |
| 3620 | |
| 3621 bool SkOpSegment::inconsistentWinding(int index, int winding, int oppWinding) co
nst { | |
| 3622 SkASSERT(winding || oppWinding); | |
| 3623 double referenceT = this->span(index).fT; | |
| 3624 int lesser = index; | |
| 3625 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | |
| 3626 if (inconsistentWinding(__FUNCTION__, lesser, winding, oppWinding)) { | |
| 3627 return true; | |
| 3628 } | |
| 3629 } | |
| 3630 do { | |
| 3631 if (inconsistentWinding(__FUNCTION__, index, winding, oppWinding)) { | |
| 3632 return true; | |
| 3633 } | |
| 3634 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); | |
| 3635 return false; | |
| 3636 } | |
| 3637 | |
| 3638 bool SkOpSegment::inconsistentWinding(const char* funName, int tIndex, int windi
ng, | |
| 3639 int oppWinding) const { | |
| 3640 const SkOpSpan& span = this->span(tIndex); | |
| 3641 if (span.fDone && !span.fSmall) { | |
| 3642 return false; | |
| 3643 } | |
| 3644 return (span.fWindSum != SK_MinS32 && span.fWindSum != winding) | |
| 3645 || (span.fOppSum != SK_MinS32 && span.fOppSum != oppWinding); | |
| 3646 } | |
| 3647 | |
| 3648 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, boo
l evenOdd) { | |
| 3649 fDoneSpans = 0; | |
| 3650 fOperand = operand; | |
| 3651 fXor = evenOdd; | |
| 3652 fPts = pts; | |
| 3653 fVerb = verb; | |
| 3654 fLoop = fMultiples = fSmall = fTiny = false; | |
| 3655 } | |
| 3656 | |
| 3657 void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIn
cludeType) { | |
| 3658 int local = spanSign(start, end); | |
| 3659 SkDEBUGCODE(bool success); | 1191 SkDEBUGCODE(bool success); |
| 3660 if (angleIncludeType == SkOpAngle::kBinarySingle) { | 1192 if (angleIncludeType == SkOpAngle::kBinarySingle) { |
| 3661 int oppLocal = oppSign(start, end); | 1193 int oppLocal = SkOpSegment::OppSign(start, end); |
| 3662 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal,
NULL); | 1194 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal,
NULL); |
| 3663 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 1195 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| 3664 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal,
NULL); | 1196 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal,
NULL); |
| 3665 } else { | 1197 } else { |
| 3666 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL); | 1198 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL); |
| 3667 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 1199 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| 3668 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL); | 1200 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL); |
| 3669 } | 1201 } |
| 3670 SkASSERT(success); | 1202 SkASSERT(success); |
| 3671 } | 1203 } |
| 3672 | 1204 |
| 3673 /* | 1205 /* |
| 3674 when we start with a vertical intersect, we try to use the dx to determine if th
e edge is to | 1206 when we start with a vertical intersect, we try to use the dx to determine if th
e edge is to |
| 3675 the left or the right of vertical. This determines if we need to add the span's | 1207 the left or the right of vertical. This determines if we need to add the span's |
| 3676 sign or not. However, this isn't enough. | 1208 sign or not. However, this isn't enough. |
| 3677 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. | 1209 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. |
| 3678 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed | 1210 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed |
| 3679 from has the same x direction as this span, the winding should change. If the dx
is opposite, then | 1211 from has the same x direction as this span, the winding should change. If the dx
is opposite, then |
| 3680 the same winding is shared by both. | 1212 the same winding is shared by both. |
| 3681 */ | 1213 */ |
| 3682 bool SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkSc
alar hitDx, | 1214 bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi
t, |
| 3683 int oppWind, SkScalar hitOppDx) { | 1215 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) { |
| 1216 SkASSERT(this == start->segment()); |
| 3684 SkASSERT(hitDx || !winding); | 1217 SkASSERT(hitDx || !winding); |
| 3685 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; | 1218 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; |
| 3686 SkASSERT(dx); | 1219 // SkASSERT(dx); |
| 3687 int windVal = windValue(SkMin32(start, end)); | 1220 int windVal = start->starter(end)->windValue(); |
| 3688 #if DEBUG_WINDING_AT_T | 1221 #if DEBUG_WINDING_AT_T |
| 3689 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d
ebugID(), winding, | 1222 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d
ebugID(), winding, |
| 3690 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); | 1223 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); |
| 3691 #endif | 1224 #endif |
| 3692 int sideWind = winding + (dx < 0 ? windVal : -windVal); | 1225 int sideWind = winding + (dx < 0 ? windVal : -windVal); |
| 3693 if (abs(winding) < abs(sideWind)) { | 1226 if (abs(winding) < abs(sideWind)) { |
| 3694 winding = sideWind; | 1227 winding = sideWind; |
| 3695 } | 1228 } |
| 3696 SkDEBUGCODE(int oppLocal = oppSign(start, end)); | 1229 SkDEBUGCODE(int oppLocal = SkOpSegment::OppSign(start, end)); |
| 3697 SkASSERT(hitOppDx || !oppWind || !oppLocal); | 1230 SkASSERT(hitOppDx || !oppWind || !oppLocal); |
| 3698 int oppWindVal = oppValue(SkMin32(start, end)); | 1231 int oppWindVal = start->starter(end)->oppValue(); |
| 3699 if (!oppWind) { | 1232 if (!oppWind) { |
| 3700 oppWind = dx < 0 ? oppWindVal : -oppWindVal; | 1233 oppWind = dx < 0 ? oppWindVal : -oppWindVal; |
| 3701 } else if (hitOppDx * dx >= 0) { | 1234 } else if (hitOppDx * dx >= 0) { |
| 3702 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); | 1235 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); |
| 3703 if (abs(oppWind) < abs(oppSideWind)) { | 1236 if (abs(oppWind) < abs(oppSideWind)) { |
| 3704 oppWind = oppSideWind; | 1237 oppWind = oppSideWind; |
| 3705 } | 1238 } |
| 3706 } | 1239 } |
| 3707 #if DEBUG_WINDING_AT_T | 1240 #if DEBUG_WINDING_AT_T |
| 3708 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind); | 1241 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind); |
| 3709 #endif | 1242 #endif |
| 3710 // if this fails to mark (because the edges are too small) inform caller to
try again | 1243 // if this fails to mark (because the edges are too small) inform caller to
try again |
| 3711 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL); | 1244 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL); |
| 3712 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 1245 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| 3713 success |= markAndChaseWinding(end, start, winding, oppWind, NULL); | 1246 success |= markAndChaseWinding(end, start, winding, oppWind, NULL); |
| 3714 return success; | 1247 return success; |
| 3715 } | 1248 } |
| 3716 | 1249 |
| 3717 bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPt
r) const { | 1250 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { |
| 3718 if (!baseAngle->inLoop()) { | 1251 SkDPoint cPt = this->dPtAtT(t); |
| 3719 return false; | 1252 int pts = SkPathOpsVerbToPoints(this->verb()); |
| 3720 } | 1253 SkDVector dxdy = (*CurveDSlopeAtT[pts])(this->pts(), t); |
| 3721 int index = *indexPtr; | 1254 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; |
| 3722 SkOpAngle* from = fTs[index].fFromAngle; | 1255 SkIntersections i; |
| 3723 SkOpAngle* to = fTs[index].fToAngle; | 1256 int oppPts = SkPathOpsVerbToPoints(opp->verb()); |
| 3724 while (++index < spanCount) { | 1257 (*CurveIntersectRay[oppPts])(opp->pts(), perp, &i); |
| 3725 SkOpAngle* nextFrom = fTs[index].fFromAngle; | 1258 int used = i.used(); |
| 3726 SkOpAngle* nextTo = fTs[index].fToAngle; | 1259 for (int index = 0; index < used; ++index) { |
| 3727 if (from != nextFrom || to != nextTo) { | 1260 if (cPt.roughlyEqual(i.pt(index))) { |
| 3728 break; | 1261 return true; |
| 3729 } | 1262 } |
| 3730 } | 1263 } |
| 3731 *indexPtr = index; | |
| 3732 return true; | |
| 3733 } | |
| 3734 | |
| 3735 // OPTIMIZE: successive calls could start were the last leaves off | |
| 3736 // or calls could specialize to walk forwards or backwards | |
| 3737 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const { | |
| 3738 int tCount = fTs.count(); | |
| 3739 for (int index = 0; index < tCount; ++index) { | |
| 3740 const SkOpSpan& span = fTs[index]; | |
| 3741 if (approximately_zero(startT - span.fT) && pt == span.fPt) { | |
| 3742 return false; | |
| 3743 } | |
| 3744 } | |
| 3745 return true; | |
| 3746 } | |
| 3747 | |
| 3748 | |
| 3749 SkOpSegment* SkOpSegment::isSimple(int* end, int* step) { | |
| 3750 return nextChase(end, step, NULL, NULL); | |
| 3751 } | |
| 3752 | |
| 3753 bool SkOpSegment::isTiny(const SkOpAngle* angle) const { | |
| 3754 int start = angle->start(); | |
| 3755 int end = angle->end(); | |
| 3756 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; | |
| 3757 return mSpan.fTiny; | |
| 3758 } | |
| 3759 | |
| 3760 bool SkOpSegment::isTiny(int index) const { | |
| 3761 return fTs[index].fTiny; | |
| 3762 } | |
| 3763 | |
| 3764 // look pair of active edges going away from coincident edge | |
| 3765 // one of them should be the continuation of other | |
| 3766 // if both are active, look to see if they both the connect to another coinciden
t pair | |
| 3767 // if at least one is a line, then make the pair coincident | |
| 3768 // if neither is a line, test for coincidence | |
| 3769 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoi
nt& otherPt, | |
| 3770 int step, bool cancel) { | |
| 3771 int otherTIndex = other->findT(otherT, otherPt, this); | |
| 3772 int next = other->nextExactSpan(otherTIndex, step); | |
| 3773 int otherMin = SkMin32(otherTIndex, next); | |
| 3774 int otherWind = other->span(otherMin).fWindValue; | |
| 3775 if (otherWind == 0) { | |
| 3776 return false; | |
| 3777 } | |
| 3778 if (next < 0) { | |
| 3779 return false; // can happen if t values were adjusted but coincident ts
were not | |
| 3780 } | |
| 3781 int tIndex = 0; | |
| 3782 do { | |
| 3783 SkOpSpan* test = &fTs[tIndex]; | |
| 3784 SkASSERT(test->fT == 0); | |
| 3785 if (test->fOther == other || test->fOtherT != 1) { | |
| 3786 continue; | |
| 3787 } | |
| 3788 SkPoint startPt, endPt; | |
| 3789 double endT; | |
| 3790 if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt,
&endPt, &endT)) { | |
| 3791 SkOpSegment* match = test->fOther; | |
| 3792 if (cancel) { | |
| 3793 match->addTCancel(startPt, endPt, other); | |
| 3794 } else { | |
| 3795 if (!match->addTCoincident(startPt, endPt, endT, other)) { | |
| 3796 return false; | |
| 3797 } | |
| 3798 } | |
| 3799 return true; | |
| 3800 } | |
| 3801 } while (fTs[++tIndex].fT == 0); | |
| 3802 return false; | 1264 return false; |
| 3803 } | 1265 } |
| 3804 | 1266 |
| 3805 // this span is excluded by the winding rule -- chase the ends | 1267 bool SkOpSegment::isXor() const { |
| 3806 // as long as they are unambiguous to mark connections as done | 1268 return fContour->isXor(); |
| 3807 // and give them the same winding value | 1269 } |
| 3808 | 1270 |
| 3809 SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) { | 1271 SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* e
nd) { |
| 3810 int step = SkSign32(endIndex - index); | 1272 int step = start->step(end); |
| 3811 int min = SkMin32(index, endIndex); | 1273 SkOpSpan* minSpan = start->starter(end); |
| 3812 markDoneBinary(min); | 1274 markDone(minSpan); |
| 3813 SkOpSpan* last = NULL; | 1275 SkOpSpanBase* last = NULL; |
| 3814 SkOpSegment* other = this; | 1276 SkOpSegment* other = this; |
| 3815 while ((other = other->nextChase(&index, &step, &min, &last))) { | 1277 while ((other = other->nextChase(&start, &step, &minSpan, &last))) { |
| 3816 if (other->done()) { | 1278 if (other->done()) { |
| 3817 SkASSERT(!last); | 1279 SkASSERT(!last); |
| 3818 break; | 1280 break; |
| 3819 } | 1281 } |
| 3820 other->markDoneBinary(min); | 1282 other->markDone(minSpan); |
| 3821 } | 1283 } |
| 3822 return last; | 1284 return last; |
| 3823 } | 1285 } |
| 3824 | 1286 |
| 3825 SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) { | 1287 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, in
t winding, |
| 3826 int step = SkSign32(endIndex - index); | 1288 SkOpSpanBase** lastPtr) { |
| 3827 int min = SkMin32(index, endIndex); | 1289 SkOpSpan* spanStart = start->starter(end); |
| 3828 markDoneUnary(min); | 1290 int step = start->step(end); |
| 3829 SkOpSpan* last = NULL; | 1291 bool success = markWinding(spanStart, winding); |
| 1292 SkOpSpanBase* last = NULL; |
| 3830 SkOpSegment* other = this; | 1293 SkOpSegment* other = this; |
| 3831 while ((other = other->nextChase(&index, &step, &min, &last))) { | 1294 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { |
| 3832 if (other->done()) { | 1295 if (spanStart->windSum() != SK_MinS32) { |
| 1296 SkASSERT(spanStart->windSum() == winding); |
| 3833 SkASSERT(!last); | 1297 SkASSERT(!last); |
| 3834 break; | 1298 break; |
| 3835 } | 1299 } |
| 3836 other->markDoneUnary(min); | 1300 (void) other->markWinding(spanStart, winding); |
| 3837 } | |
| 3838 return last; | |
| 3839 } | |
| 3840 | |
| 3841 bool SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, SkOpS
pan** lastPtr) { | |
| 3842 int index = angle->start(); | |
| 3843 int endIndex = angle->end(); | |
| 3844 return markAndChaseWinding(index, endIndex, winding, lastPtr); | |
| 3845 } | |
| 3846 | |
| 3847 bool SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, SkOp
Span** lastPtr) { | |
| 3848 int min = SkMin32(index, endIndex); | |
| 3849 int step = SkSign32(endIndex - index); | |
| 3850 bool success = markWinding(min, winding); | |
| 3851 SkOpSpan* last = NULL; | |
| 3852 SkOpSegment* other = this; | |
| 3853 while ((other = other->nextChase(&index, &step, &min, &last))) { | |
| 3854 if (other->fTs[min].fWindSum != SK_MinS32) { | |
| 3855 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoo
p); | |
| 3856 SkASSERT(!last); | |
| 3857 break; | |
| 3858 } | |
| 3859 (void) other->markWinding(min, winding); | |
| 3860 } | 1301 } |
| 3861 if (lastPtr) { | 1302 if (lastPtr) { |
| 3862 *lastPtr = last; | 1303 *lastPtr = last; |
| 3863 } | 1304 } |
| 3864 return success; | 1305 return success; |
| 3865 } | 1306 } |
| 3866 | 1307 |
| 3867 bool SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int
oppWinding, | 1308 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, |
| 3868 SkOpSpan** lastPtr) { | 1309 int winding, int oppWinding, SkOpSpanBase** lastPtr) { |
| 3869 int min = SkMin32(index, endIndex); | 1310 SkOpSpan* spanStart = start->starter(end); |
| 3870 int step = SkSign32(endIndex - index); | 1311 int step = start->step(end); |
| 3871 bool success = markWinding(min, winding, oppWinding); | 1312 bool success = markWinding(spanStart, winding, oppWinding); |
| 3872 SkOpSpan* last = NULL; | 1313 SkOpSpanBase* last = NULL; |
| 3873 SkOpSegment* other = this; | 1314 SkOpSegment* other = this; |
| 3874 while ((other = other->nextChase(&index, &step, &min, &last))) { | 1315 while ((other = other->nextChase(&start, &step, &spanStart, &last))) { |
| 3875 if (other->fTs[min].fWindSum != SK_MinS32) { | 1316 if (spanStart->windSum() != SK_MinS32) { |
| 3876 #ifdef SK_DEBUG | 1317 if (this->operand() == other->operand()) { |
| 3877 if (!other->fTs[min].fLoop) { | 1318 SkASSERT(spanStart->windSum() == winding); |
| 3878 if (fOperand == other->fOperand) { | 1319 if (spanStart->oppSum() != oppWinding) { |
| 3879 // FIXME: this is probably a bug -- rects4 asserts here | 1320 this->globalState()->setWindingFailed(); |
| 3880 // SkASSERT(other->fTs[min].fWindSum == winding); | 1321 return false; |
| 3881 // FIXME: this is probably a bug -- rects3 asserts here | |
| 3882 // SkASSERT(other->fTs[min].fOppSum == oppWinding); | |
| 3883 } else { | |
| 3884 // FIXME: this is probably a bug -- issue414409b asserts here | |
| 3885 // SkASSERT(other->fTs[min].fWindSum == oppWinding); | |
| 3886 // FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here | |
| 3887 // SkASSERT(other->fTs[min].fOppSum == winding); | |
| 3888 } | 1322 } |
| 1323 } else { |
| 1324 SkASSERT(spanStart->windSum() == oppWinding); |
| 1325 SkASSERT(spanStart->oppSum() == winding); |
| 3889 } | 1326 } |
| 3890 SkASSERT(!last); | 1327 SkASSERT(!last); |
| 3891 #endif | |
| 3892 break; | 1328 break; |
| 3893 } | 1329 } |
| 3894 if (fOperand == other->fOperand) { | 1330 if (this->operand() == other->operand()) { |
| 3895 (void) other->markWinding(min, winding, oppWinding); | 1331 (void) other->markWinding(spanStart, winding, oppWinding); |
| 3896 } else { | 1332 } else { |
| 3897 (void) other->markWinding(min, oppWinding, winding); | 1333 (void) other->markWinding(spanStart, oppWinding, winding); |
| 3898 } | 1334 } |
| 3899 } | 1335 } |
| 3900 if (lastPtr) { | 1336 if (lastPtr) { |
| 3901 *lastPtr = last; | 1337 *lastPtr = last; |
| 3902 } | 1338 } |
| 3903 return success; | 1339 return success; |
| 3904 } | 1340 } |
| 3905 | 1341 |
| 3906 bool SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int o
ppWinding, | 1342 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpA
ngle* angle) { |
| 3907 SkOpSpan** lastPtr) { | |
| 3908 int start = angle->start(); | |
| 3909 int end = angle->end(); | |
| 3910 return markAndChaseWinding(start, end, winding, oppWinding, lastPtr); | |
| 3911 } | |
| 3912 | |
| 3913 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle
* angle) { | |
| 3914 SkASSERT(angle->segment() == this); | 1343 SkASSERT(angle->segment() == this); |
| 3915 if (UseInnerWinding(maxWinding, sumWinding)) { | 1344 if (UseInnerWinding(maxWinding, sumWinding)) { |
| 3916 maxWinding = sumWinding; | 1345 maxWinding = sumWinding; |
| 3917 } | 1346 } |
| 3918 SkOpSpan* last; | 1347 SkOpSpanBase* last; |
| 3919 SkAssertResult(markAndChaseWinding(angle, maxWinding, &last)); | 1348 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last); |
| 3920 #if DEBUG_WINDING | 1349 #if DEBUG_WINDING |
| 3921 if (last) { | 1350 if (last) { |
| 3922 SkDebugf("%s last id=%d windSum=", __FUNCTION__, | 1351 SkDebugf("%s last seg=%d span=%d", __FUNCTION__, |
| 3923 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); | 1352 last->segment()->debugID(), last->debugID()); |
| 3924 SkPathOpsDebug::WindingPrintf(last->fWindSum); | 1353 if (!last->final()) { |
| 3925 SkDebugf(" small=%d\n", last->fSmall); | 1354 SkDebugf(" windSum="); |
| 1355 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum()); |
| 1356 } |
| 1357 SkDebugf("\n"); |
| 3926 } | 1358 } |
| 3927 #endif | 1359 #endif |
| 3928 return last; | 1360 return last; |
| 3929 } | 1361 } |
| 3930 | 1362 |
| 3931 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWindi
ng, | 1363 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxW
inding, |
| 3932 int oppSumWinding, const SkOpAngle* angle) { | 1364 int oppSumWinding, const SkOpAngle* angle) { |
| 3933 SkASSERT(angle->segment() == this); | 1365 SkASSERT(angle->segment() == this); |
| 3934 if (UseInnerWinding(maxWinding, sumWinding)) { | 1366 if (UseInnerWinding(maxWinding, sumWinding)) { |
| 3935 maxWinding = sumWinding; | 1367 maxWinding = sumWinding; |
| 3936 } | 1368 } |
| 3937 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { | 1369 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { |
| 3938 oppMaxWinding = oppSumWinding; | 1370 oppMaxWinding = oppSumWinding; |
| 3939 } | 1371 } |
| 3940 SkOpSpan* last; | 1372 SkOpSpanBase* last = NULL; |
| 3941 // caller doesn't require that this marks anything | 1373 // caller doesn't require that this marks anything |
| 3942 (void) markAndChaseWinding(angle, maxWinding, oppMaxWinding, &last); | 1374 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxW
inding, &last); |
| 3943 #if DEBUG_WINDING | 1375 #if DEBUG_WINDING |
| 3944 if (last) { | 1376 if (last) { |
| 3945 SkDebugf("%s last id=%d windSum=", __FUNCTION__, | 1377 SkDebugf("%s last segment=%d span=%d", __FUNCTION__, |
| 3946 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); | 1378 last->segment()->debugID(), last->debugID()); |
| 3947 SkPathOpsDebug::WindingPrintf(last->fWindSum); | 1379 if (!last->final()) { |
| 3948 SkDebugf(" small=%d\n", last->fSmall); | 1380 SkDebugf(" windSum="); |
| 1381 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum()); |
| 1382 } |
| 1383 SkDebugf(" \n"); |
| 3949 } | 1384 } |
| 3950 #endif | 1385 #endif |
| 3951 return last; | 1386 return last; |
| 3952 } | 1387 } |
| 3953 | 1388 |
| 3954 // FIXME: this should also mark spans with equal (x,y) | 1389 void SkOpSegment::markDone(SkOpSpan* span) { |
| 3955 // This may be called when the segment is already marked done. While this | 1390 SkASSERT(this == span->segment()); |
| 3956 // wastes time, it shouldn't do any more than spin through the T spans. | 1391 if (span->done()) { |
| 3957 // OPTIMIZATION: abort on first done found (assuming that this code is | 1392 return; |
| 3958 // always called to mark segments done). | |
| 3959 void SkOpSegment::markDone(int index, int winding) { | |
| 3960 // SkASSERT(!done()); | |
| 3961 SkASSERT(winding); | |
| 3962 double referenceT = fTs[index].fT; | |
| 3963 int lesser = index; | |
| 3964 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | |
| 3965 markOneDone(__FUNCTION__, lesser, winding); | |
| 3966 } | 1393 } |
| 3967 do { | 1394 #if DEBUG_MARK_DONE |
| 3968 markOneDone(__FUNCTION__, index, winding); | 1395 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum()); |
| 3969 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | 1396 #endif |
| 1397 span->setDone(true); |
| 1398 ++fDoneCount; |
| 3970 debugValidate(); | 1399 debugValidate(); |
| 3971 } | 1400 } |
| 3972 | 1401 |
| 3973 void SkOpSegment::markDoneBinary(int index) { | 1402 bool SkOpSegment::markWinding(SkOpSpan* span, int winding) { |
| 3974 double referenceT = fTs[index].fT; | 1403 SkASSERT(this == span->segment()); |
| 3975 int lesser = index; | 1404 SkASSERT(winding); |
| 3976 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | 1405 if (span->done()) { |
| 3977 markOneDoneBinary(__FUNCTION__, lesser); | |
| 3978 } | |
| 3979 do { | |
| 3980 markOneDoneBinary(__FUNCTION__, index); | |
| 3981 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | |
| 3982 debugValidate(); | |
| 3983 } | |
| 3984 | |
| 3985 void SkOpSegment::markDoneFinal(int index) { | |
| 3986 double referenceT = fTs[index].fT; | |
| 3987 int lesser = index; | |
| 3988 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | |
| 3989 markOneDoneFinal(__FUNCTION__, lesser); | |
| 3990 } | |
| 3991 do { | |
| 3992 markOneDoneFinal(__FUNCTION__, index); | |
| 3993 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | |
| 3994 debugValidate(); | |
| 3995 } | |
| 3996 | |
| 3997 void SkOpSegment::markDoneUnary(int index) { | |
| 3998 double referenceT = fTs[index].fT; | |
| 3999 int lesser = index; | |
| 4000 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | |
| 4001 markOneDoneUnary(__FUNCTION__, lesser); | |
| 4002 } | |
| 4003 do { | |
| 4004 markOneDoneUnary(__FUNCTION__, index); | |
| 4005 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | |
| 4006 debugValidate(); | |
| 4007 } | |
| 4008 | |
| 4009 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) { | |
| 4010 SkOpSpan* span; | |
| 4011 (void) markOneWinding(funName, tIndex, winding, &span); // allowed to do no
thing | |
| 4012 if (span->fDone) { | |
| 4013 return; | |
| 4014 } | |
| 4015 span->fDone = true; | |
| 4016 ++fDoneSpans; | |
| 4017 } | |
| 4018 | |
| 4019 void SkOpSegment::markOneDoneFinal(const char* funName, int tIndex) { | |
| 4020 SkOpSpan* span = &fTs[tIndex]; | |
| 4021 if (span->fDone) { | |
| 4022 return; | |
| 4023 } | |
| 4024 span->fDone = true; | |
| 4025 ++fDoneSpans; | |
| 4026 } | |
| 4027 | |
| 4028 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) { | |
| 4029 SkOpSpan* span = verifyOneWinding(funName, tIndex); | |
| 4030 if (!span) { | |
| 4031 return; | |
| 4032 } | |
| 4033 SkASSERT(!span->fDone); | |
| 4034 span->fDone = true; | |
| 4035 ++fDoneSpans; | |
| 4036 } | |
| 4037 | |
| 4038 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) { | |
| 4039 SkOpSpan* span = verifyOneWindingU(funName, tIndex); | |
| 4040 if (!span) { | |
| 4041 return; | |
| 4042 } | |
| 4043 if (span->fWindSum == SK_MinS32) { | |
| 4044 SkDebugf("%s uncomputed\n", __FUNCTION__); | |
| 4045 } | |
| 4046 SkASSERT(!span->fDone); | |
| 4047 span->fDone = true; | |
| 4048 ++fDoneSpans; | |
| 4049 } | |
| 4050 | |
| 4051 bool SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding, S
kOpSpan** lastPtr) { | |
| 4052 SkOpSpan* span = &fTs[tIndex]; | |
| 4053 if (lastPtr) { | |
| 4054 *lastPtr = span; | |
| 4055 } | |
| 4056 if (span->fDone && !span->fSmall) { | |
| 4057 return false; | 1406 return false; |
| 4058 } | 1407 } |
| 4059 #if DEBUG_MARK_DONE | 1408 #if DEBUG_MARK_DONE |
| 4060 debugShowNewWinding(funName, *span, winding); | 1409 debugShowNewWinding(__FUNCTION__, span, winding); |
| 4061 #endif | 1410 #endif |
| 4062 SkASSERT(span->fWindSum == SK_MinS32 || span->fWindSum == winding); | 1411 span->setWindSum(winding); |
| 4063 #if DEBUG_LIMIT_WIND_SUM | 1412 debugValidate(); |
| 4064 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM); | |
| 4065 #endif | |
| 4066 span->fWindSum = winding; | |
| 4067 return true; | 1413 return true; |
| 4068 } | 1414 } |
| 4069 | 1415 |
| 4070 bool SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding, | 1416 bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) { |
| 4071 int oppWinding, SkOpSpan** lastPtr) { | 1417 SkASSERT(this == span->segment()); |
| 4072 SkOpSpan* span = &fTs[tIndex]; | 1418 SkASSERT(winding || oppWinding); |
| 4073 if (span->fDone && !span->fSmall) { | 1419 if (span->done()) { |
| 4074 return false; | 1420 return false; |
| 4075 } | 1421 } |
| 4076 #if DEBUG_MARK_DONE | 1422 #if DEBUG_MARK_DONE |
| 4077 debugShowNewWinding(funName, *span, winding, oppWinding); | 1423 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding); |
| 4078 #endif | 1424 #endif |
| 4079 SkASSERT(span->fWindSum == SK_MinS32 || span->fWindSum == winding); | 1425 span->setWindSum(winding); |
| 4080 #if DEBUG_LIMIT_WIND_SUM | 1426 span->setOppSum(oppWinding); |
| 4081 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM); | |
| 4082 #endif | |
| 4083 span->fWindSum = winding; | |
| 4084 SkASSERT(span->fOppSum == SK_MinS32 || span->fOppSum == oppWinding); | |
| 4085 #if DEBUG_LIMIT_WIND_SUM | |
| 4086 SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM); | |
| 4087 #endif | |
| 4088 span->fOppSum = oppWinding; | |
| 4089 debugValidate(); | 1427 debugValidate(); |
| 4090 if (lastPtr) { | |
| 4091 *lastPtr = span; | |
| 4092 } | |
| 4093 return true; | 1428 return true; |
| 4094 } | 1429 } |
| 4095 | 1430 |
| 4096 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 1431 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub
le testT, |
| 4097 bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const { | 1432 const SkPoint& testPt) const { |
| 4098 SkASSERT(fVerb != SkPath::kLine_Verb); | 1433 const SkOpSegment* baseParent = base->segment(); |
| 4099 SkPoint edge[4]; | 1434 if (this == baseParent && this == testParent && precisely_equal(base->fT, te
stT)) { |
| 4100 subDivide(tStart, tEnd, edge); | 1435 return true; |
| 4101 int points = SkPathOpsVerbToPoints(fVerb); | |
| 4102 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; | |
| 4103 bool sumSet = false; | |
| 4104 if (fVerb == SkPath::kCubic_Verb) { | |
| 4105 SkDCubic cubic; | |
| 4106 cubic.set(edge); | |
| 4107 double inflectionTs[2]; | |
| 4108 int inflections = cubic.findInflections(inflectionTs); | |
| 4109 // FIXME: this fixes cubicOp114 and breaks cubicOp58d | |
| 4110 // the trouble is that cubics with inflections confuse whether the curve
breaks towards | |
| 4111 // or away, which in turn is used to determine if it is on the far right
or left. | |
| 4112 // Probably a totally different approach is in order. At one time I trie
d to project a | |
| 4113 // horizontal ray to determine winding, but was confused by how to map t
he vertically | |
| 4114 // oriented winding computation over. | |
| 4115 if (0 && inflections) { | |
| 4116 double tLo = this->span(tStart).fT; | |
| 4117 double tHi = this->span(tEnd).fT; | |
| 4118 double tLoStart = tLo; | |
| 4119 for (int index = 0; index < inflections; ++index) { | |
| 4120 if (between(tLo, inflectionTs[index], tHi)) { | |
| 4121 tLo = inflectionTs[index]; | |
| 4122 } | |
| 4123 } | |
| 4124 if (tLo != tLoStart && tLo != tHi) { | |
| 4125 SkDPoint sub[2]; | |
| 4126 sub[0] = cubic.ptAtT(tLo); | |
| 4127 sub[1].set(edge[3]); | |
| 4128 SkDPoint ctrl[2]; | |
| 4129 SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl); | |
| 4130 edge[0] = sub[0].asSkPoint(); | |
| 4131 edge[1] = ctrl[0].asSkPoint(); | |
| 4132 edge[2] = ctrl[1].asSkPoint(); | |
| 4133 sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY); | |
| 4134 } | |
| 4135 } | |
| 4136 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); | |
| 4137 if (edge[1].fY < lesser && edge[2].fY < lesser) { | |
| 4138 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1]
.fY} }}; | |
| 4139 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3]
.fY} }}; | |
| 4140 if (SkIntersections::Test(tangent1, tangent2)) { | |
| 4141 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
| 4142 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); | |
| 4143 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); | |
| 4144 sumSet = true; | |
| 4145 } | |
| 4146 } | |
| 4147 } | 1436 } |
| 4148 if (!sumSet) { | 1437 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) { |
| 4149 for (int idx = 0; idx < points; ++idx){ | 1438 return false; |
| 4150 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[
idx].fY); | |
| 4151 } | |
| 4152 } | 1439 } |
| 4153 if (fVerb == SkPath::kCubic_Verb) { | 1440 return !ptsDisjoint(base->fT, base->fPt, testT, testPt); |
| 4154 SkDCubic cubic; | |
| 4155 cubic.set(edge); | |
| 4156 *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine(); | |
| 4157 } else { | |
| 4158 SkDQuad quad; | |
| 4159 quad.set(edge); | |
| 4160 *swap = sum > 0 && !quad.monotonicInY(); | |
| 4161 } | |
| 4162 return sum <= 0; | |
| 4163 } | 1441 } |
| 4164 | 1442 |
| 4165 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { | 1443 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) { |
| 4166 SkASSERT(fVerb != SkPath::kLine_Verb); | 1444 if (last) { |
| 4167 if (fVerb == SkPath::kQuad_Verb) { | 1445 *last = endSpan; |
| 4168 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
| 4169 return dst.monotonicInY(); | |
| 4170 } | |
| 4171 SkASSERT(fVerb == SkPath::kCubic_Verb); | |
| 4172 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
| 4173 return dst.monotonicInY(); | |
| 4174 } | |
| 4175 | |
| 4176 bool SkOpSegment::serpentine(int tStart, int tEnd) const { | |
| 4177 if (fVerb != SkPath::kCubic_Verb) { | |
| 4178 return false; | |
| 4179 } | |
| 4180 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
| 4181 return dst.serpentine(); | |
| 4182 } | |
| 4183 | |
| 4184 SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) { | |
| 4185 SkOpSpan& span = fTs[tIndex]; | |
| 4186 if (span.fDone) { | |
| 4187 return NULL; | |
| 4188 } | |
| 4189 #if DEBUG_MARK_DONE | |
| 4190 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum); | |
| 4191 #endif | |
| 4192 // If the prior angle in the sort is unorderable, the winding sum may not be com
putable. | |
| 4193 // To enable the assert, the 'prior is unorderable' state could be | |
| 4194 // piped down to this test, but not sure it's worth it. | |
| 4195 // (Once the sort order is stored in the span, this test may be feasible.) | |
| 4196 // SkASSERT(span.fWindSum != SK_MinS32); | |
| 4197 // SkASSERT(span.fOppSum != SK_MinS32); | |
| 4198 return &span; | |
| 4199 } | |
| 4200 | |
| 4201 SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) { | |
| 4202 SkOpSpan& span = fTs[tIndex]; | |
| 4203 if (span.fDone) { | |
| 4204 return NULL; | |
| 4205 } | |
| 4206 #if DEBUG_MARK_DONE | |
| 4207 debugShowNewWinding(funName, span, span.fWindSum); | |
| 4208 #endif | |
| 4209 // If the prior angle in the sort is unorderable, the winding sum may not be com
putable. | |
| 4210 // To enable the assert, the 'prior is unorderable' state could be | |
| 4211 // piped down to this test, but not sure it's worth it. | |
| 4212 // (Once the sort order is stored in the span, this test may be feasible.) | |
| 4213 // SkASSERT(span.fWindSum != SK_MinS32); | |
| 4214 return &span; | |
| 4215 } | |
| 4216 | |
| 4217 bool SkOpSegment::markWinding(int index, int winding) { | |
| 4218 // SkASSERT(!done()); | |
| 4219 SkASSERT(winding); | |
| 4220 double referenceT = fTs[index].fT; | |
| 4221 int lesser = index; | |
| 4222 bool success = false; | |
| 4223 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | |
| 4224 success |= markOneWinding(__FUNCTION__, lesser, winding, NULL); | |
| 4225 } | |
| 4226 do { | |
| 4227 success |= markOneWinding(__FUNCTION__, index, winding, NULL); | |
| 4228 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); | |
| 4229 debugValidate(); | |
| 4230 return success; | |
| 4231 } | |
| 4232 | |
| 4233 bool SkOpSegment::markWinding(int index, int winding, int oppWinding) { | |
| 4234 // SkASSERT(!done()); | |
| 4235 SkASSERT(winding || oppWinding); | |
| 4236 double referenceT = fTs[index].fT; | |
| 4237 int lesser = index; | |
| 4238 bool success = false; | |
| 4239 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | |
| 4240 success |= markOneWinding(__FUNCTION__, lesser, winding, oppWinding, NUL
L); | |
| 4241 } | |
| 4242 do { | |
| 4243 success |= markOneWinding(__FUNCTION__, index, winding, oppWinding, NULL
); | |
| 4244 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); | |
| 4245 debugValidate(); | |
| 4246 return success; | |
| 4247 } | |
| 4248 | |
| 4249 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) { | |
| 4250 int nextDoorWind = SK_MaxS32; | |
| 4251 int nextOppWind = SK_MaxS32; | |
| 4252 // prefer exact matches | |
| 4253 if (tIndex > 0) { | |
| 4254 const SkOpSpan& below = fTs[tIndex - 1]; | |
| 4255 if (below.fT == t) { | |
| 4256 nextDoorWind = below.fWindValue; | |
| 4257 nextOppWind = below.fOppValue; | |
| 4258 } | |
| 4259 } | |
| 4260 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { | |
| 4261 const SkOpSpan& above = fTs[tIndex + 1]; | |
| 4262 if (above.fT == t) { | |
| 4263 nextDoorWind = above.fWindValue; | |
| 4264 nextOppWind = above.fOppValue; | |
| 4265 } | |
| 4266 } | |
| 4267 if (nextDoorWind == SK_MaxS32 && tIndex > 0) { | |
| 4268 const SkOpSpan& below = fTs[tIndex - 1]; | |
| 4269 if (approximately_negative(t - below.fT)) { | |
| 4270 nextDoorWind = below.fWindValue; | |
| 4271 nextOppWind = below.fOppValue; | |
| 4272 } | |
| 4273 } | |
| 4274 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { | |
| 4275 const SkOpSpan& above = fTs[tIndex + 1]; | |
| 4276 if (approximately_negative(above.fT - t)) { | |
| 4277 nextDoorWind = above.fWindValue; | |
| 4278 nextOppWind = above.fOppValue; | |
| 4279 } | |
| 4280 } | |
| 4281 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) { | |
| 4282 const SkOpSpan& below = fTs[tIndex - 1]; | |
| 4283 nextDoorWind = below.fWindValue; | |
| 4284 nextOppWind = below.fOppValue; | |
| 4285 } | |
| 4286 if (nextDoorWind != SK_MaxS32) { | |
| 4287 SkOpSpan& newSpan = fTs[tIndex]; | |
| 4288 newSpan.fWindValue = nextDoorWind; | |
| 4289 newSpan.fOppValue = nextOppWind; | |
| 4290 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) { | |
| 4291 newSpan.fDone = true; | |
| 4292 ++fDoneSpans; | |
| 4293 } | |
| 4294 } | |
| 4295 } | |
| 4296 | |
| 4297 bool SkOpSegment::nextCandidate(int* start, int* end) const { | |
| 4298 while (fTs[*end].fDone) { | |
| 4299 if (fTs[*end].fT == 1) { | |
| 4300 return false; | |
| 4301 } | |
| 4302 ++(*end); | |
| 4303 } | |
| 4304 *start = *end; | |
| 4305 *end = nextExactSpan(*start, 1); | |
| 4306 return true; | |
| 4307 } | |
| 4308 | |
| 4309 static SkOpSegment* set_last(SkOpSpan** last, const SkOpSpan* endSpan) { | |
| 4310 if (last && !endSpan->fSmall) { | |
| 4311 *last = const_cast<SkOpSpan*>(endSpan); // FIXME: get rid of cast | |
| 4312 } | 1446 } |
| 4313 return NULL; | 1447 return NULL; |
| 4314 } | 1448 } |
| 4315 | 1449 |
| 4316 SkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, | 1450 bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en
d) const { |
| 4317 SkOpSpan** last) const { | 1451 SkASSERT(fVerb != SkPath::kLine_Verb); |
| 4318 int origIndex = *indexPtr; | 1452 if (fVerb == SkPath::kQuad_Verb) { |
| 1453 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t()); |
| 1454 return dst.monotonicInY(); |
| 1455 } |
| 1456 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1457 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); |
| 1458 return dst.monotonicInY(); |
| 1459 } |
| 1460 |
| 1461 bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, |
| 1462 SkOpSpanBase** end) { |
| 1463 while (span->final() || span->upCast()->done()) { |
| 1464 if (span->final()) { |
| 1465 return false; |
| 1466 } |
| 1467 span = span->upCast()->next(); |
| 1468 } |
| 1469 *start = span; |
| 1470 *end = span->upCast()->next(); |
| 1471 return true; |
| 1472 } |
| 1473 |
| 1474 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
pan** minPtr, |
| 1475 SkOpSpanBase** last) const { |
| 1476 SkOpSpanBase* origStart = *startPtr; |
| 4319 int step = *stepPtr; | 1477 int step = *stepPtr; |
| 4320 int end = nextExactSpan(origIndex, step); | 1478 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->
prev(); |
| 4321 SkASSERT(end >= 0); | 1479 SkASSERT(endSpan); |
| 4322 const SkOpSpan& endSpan = this->span(end); | 1480 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAn
gle(); |
| 4323 SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle; | 1481 SkOpSpanBase* foundSpan; |
| 4324 int foundIndex; | 1482 SkOpSpanBase* otherEnd; |
| 4325 int otherEnd; | |
| 4326 SkOpSegment* other; | 1483 SkOpSegment* other; |
| 4327 if (angle == NULL) { | 1484 if (angle == NULL) { |
| 4328 if (endSpan.fT != 0 && endSpan.fT != 1) { | 1485 if (endSpan->t() != 0 && endSpan->t() != 1) { |
| 4329 return NULL; | 1486 return NULL; |
| 4330 } | 1487 } |
| 4331 other = endSpan.fOther; | 1488 SkOpPtT* otherPtT = endSpan->ptT()->next(); |
| 4332 foundIndex = endSpan.fOtherIndex; | 1489 other = otherPtT->segment(); |
| 4333 otherEnd = other->nextExactSpan(foundIndex, step); | 1490 foundSpan = otherPtT->span(); |
| 1491 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev(); |
| 4334 } else { | 1492 } else { |
| 4335 int loopCount = angle->loopCount(); | 1493 int loopCount = angle->loopCount(); |
| 4336 if (loopCount > 2) { | 1494 if (loopCount > 2) { |
| 4337 return set_last(last, &endSpan); | 1495 return set_last(last, endSpan); |
| 4338 } | 1496 } |
| 4339 const SkOpAngle* next = angle->next(); | 1497 const SkOpAngle* next = angle->next(); |
| 4340 if (NULL == next) { | 1498 if (NULL == next) { |
| 4341 return NULL; | 1499 return NULL; |
| 4342 } | 1500 } |
| 4343 if (angle->sign() != next->sign()) { | |
| 4344 #if DEBUG_WINDING | 1501 #if DEBUG_WINDING |
| 1502 if (angle->sign() != next->sign() && !angle->segment()->contour()->isXor
() |
| 1503 && !next->segment()->contour()->isXor()) { |
| 4345 SkDebugf("%s mismatched signs\n", __FUNCTION__); | 1504 SkDebugf("%s mismatched signs\n", __FUNCTION__); |
| 1505 } |
| 4346 #endif | 1506 #endif |
| 4347 // return set_last(last, &endSpan); | |
| 4348 } | |
| 4349 other = next->segment(); | 1507 other = next->segment(); |
| 4350 foundIndex = end = next->start(); | 1508 foundSpan = endSpan = next->start(); |
| 4351 otherEnd = next->end(); | 1509 otherEnd = next->end(); |
| 4352 } | 1510 } |
| 4353 int foundStep = foundIndex < otherEnd ? 1 : -1; | 1511 int foundStep = foundSpan->step(otherEnd); |
| 4354 if (*stepPtr != foundStep) { | 1512 if (*stepPtr != foundStep) { |
| 4355 return set_last(last, &endSpan); | 1513 return set_last(last, endSpan); |
| 4356 } | 1514 } |
| 4357 SkASSERT(*indexPtr >= 0); | 1515 SkASSERT(*startPtr); |
| 4358 if (otherEnd < 0) { | 1516 if (!otherEnd) { |
| 4359 return NULL; | 1517 return NULL; |
| 4360 } | 1518 } |
| 4361 // SkASSERT(otherEnd >= 0); | 1519 // SkASSERT(otherEnd >= 0); |
| 4362 #if 1 | 1520 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast(); |
| 4363 int origMin = origIndex + (step < 0 ? step : 0); | 1521 SkOpSpan* foundMin = foundSpan->starter(otherEnd); |
| 4364 const SkOpSpan& orig = this->span(origMin); | 1522 if (foundMin->windValue() != origMin->windValue() |
| 4365 #endif | 1523 || foundMin->oppValue() != origMin->oppValue()) { |
| 4366 int foundMin = SkMin32(foundIndex, otherEnd); | 1524 return set_last(last, endSpan); |
| 4367 #if 1 | |
| 4368 const SkOpSpan& found = other->span(foundMin); | |
| 4369 if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue
) { | |
| 4370 return set_last(last, &endSpan); | |
| 4371 } | 1525 } |
| 4372 #endif | 1526 *startPtr = foundSpan; |
| 4373 *indexPtr = foundIndex; | |
| 4374 *stepPtr = foundStep; | 1527 *stepPtr = foundStep; |
| 4375 if (minPtr) { | 1528 if (minPtr) { |
| 4376 *minPtr = foundMin; | 1529 *minPtr = foundMin; |
| 4377 } | 1530 } |
| 4378 return other; | 1531 return other; |
| 4379 } | 1532 } |
| 4380 | 1533 |
| 4381 // This has callers for two different situations: one establishes the end | 1534 static void clear_visited(SkOpSpan* span) { |
| 4382 // of the current span, and one establishes the beginning of the next span | 1535 // reset visited flag back to false |
| 4383 // (thus the name). When this is looking for the end of the current span, | 1536 do { |
| 4384 // coincidence is found when the beginning Ts contain -step and the end | 1537 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; |
| 4385 // contains step. When it is looking for the beginning of the next, the | 1538 while ((ptT = ptT->next()) != stopPtT) { |
| 4386 // first Ts found can be ignored and the last Ts should contain -step. | 1539 SkOpSegment* opp = ptT->segment(); |
| 4387 // OPTIMIZATION: probably should split into two functions | 1540 opp->resetVisited(); |
| 4388 int SkOpSegment::nextSpan(int from, int step) const { | |
| 4389 const SkOpSpan& fromSpan = fTs[from]; | |
| 4390 int count = fTs.count(); | |
| 4391 int to = from; | |
| 4392 while (step > 0 ? ++to < count : --to >= 0) { | |
| 4393 const SkOpSpan& span = fTs[to]; | |
| 4394 if (approximately_zero(span.fT - fromSpan.fT)) { | |
| 4395 continue; | |
| 4396 } | 1541 } |
| 4397 return to; | 1542 } while ((span = span->next()->upCastable())); |
| 1543 } |
| 1544 |
| 1545 // look for pairs of undetected coincident curves |
| 1546 // assumes that segments going in have visited flag clear |
| 1547 // curve/curve intersection should now do a pretty good job of finding coinciden
t runs so |
| 1548 // this may be only be necessary for line/curve pairs -- so skip unless this is
a line and the |
| 1549 // the opp is not a line |
| 1550 void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
* allocator) { |
| 1551 if (this->verb() != SkPath::kLine_Verb) { |
| 1552 return; |
| 4398 } | 1553 } |
| 4399 return -1; | 1554 SkOpSpan* prior = NULL; |
| 4400 } | 1555 SkOpSpan* span = &fHead; |
| 4401 | 1556 do { |
| 4402 // FIXME | 1557 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT; |
| 4403 // this returns at any difference in T, vs. a preset minimum. It may be | 1558 SkASSERT(ptT->span() == span); |
| 4404 // that all callers to nextSpan should use this instead. | 1559 while ((ptT = ptT->next()) != spanStopPtT) { |
| 4405 int SkOpSegment::nextExactSpan(int from, int step) const { | 1560 SkOpSegment* opp = ptT->span()->segment(); |
| 4406 int to = from; | 1561 if (opp->setVisited()) { |
| 4407 if (step < 0) { | 1562 continue; |
| 4408 const SkOpSpan& fromSpan = fTs[from]; | 1563 } |
| 4409 while (--to >= 0) { | 1564 if (opp->verb() == SkPath::kLine_Verb) { |
| 4410 const SkOpSpan& span = fTs[to]; | 1565 continue; |
| 4411 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) { | 1566 } |
| 4412 continue; | 1567 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if
the opposite |
| 4413 } | 1568 // segment is coincident then
no more coincidence |
| 4414 return to; | 1569 // needs to be detected. This
may not be true. |
| 1570 continue; |
| 1571 } |
| 1572 if (span->containsCoinEnd(opp)) { |
| 1573 continue; |
| 1574 } |
| 1575 // if already visited and visited again, check for coin |
| 1576 if (span == &fHead) { |
| 1577 continue; |
| 1578 } |
| 1579 SkOpPtT* priorPtT = NULL, * priorStopPtT; |
| 1580 // find prior span containing opp segment |
| 1581 SkOpSegment* priorOpp = NULL; |
| 1582 prior = span; |
| 1583 while (!priorOpp && (prior = prior->prev())) { |
| 1584 priorStopPtT = priorPtT = prior->ptT(); |
| 1585 while ((priorPtT = priorPtT->next()) != priorStopPtT) { |
| 1586 SkOpSegment* segment = priorPtT->span()->segment(); |
| 1587 if (segment == opp) { |
| 1588 priorOpp = opp; |
| 1589 break; |
| 1590 } |
| 1591 } |
| 1592 } |
| 1593 if (!priorOpp) { |
| 1594 continue; |
| 1595 } |
| 1596 SkOpPtT* oppStart = prior->ptT(); |
| 1597 SkOpPtT* oppEnd = span->ptT(); |
| 1598 bool swapped = priorPtT->fT > ptT->fT; |
| 1599 if (swapped) { |
| 1600 SkTSwap(priorPtT, ptT); |
| 1601 SkTSwap(oppStart, oppEnd); |
| 1602 } |
| 1603 bool flipped = oppStart->fT > oppEnd->fT; |
| 1604 bool coincident; |
| 1605 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)
) { |
| 1606 goto swapBack; |
| 1607 } |
| 1608 { |
| 1609 // average t, find mid pt |
| 1610 double midT = (prior->t() + span->t()) / 2; |
| 1611 SkPoint midPt = this->ptAtT(midT); |
| 1612 coincident = true; |
| 1613 // if the mid pt is not near either end pt, project perpendicula
r through opp seg |
| 1614 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) |
| 1615 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { |
| 1616 coincident = false; |
| 1617 SkIntersections i; |
| 1618 int ptCount = SkPathOpsVerbToPoints(this->verb()); |
| 1619 SkVector dxdy = (*CurveSlopeAtT[ptCount])(pts(), midT); |
| 1620 SkDLine ray = {{{midPt.fX, midPt.fY}, |
| 1621 {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}}; |
| 1622 int oppPtCount = SkPathOpsVerbToPoints(opp->verb()); |
| 1623 (*CurveIntersectRay[oppPtCount])(opp->pts(), ray, &i); |
| 1624 // measure distance and see if it's small enough to denote c
oincidence |
| 1625 for (int index = 0; index < i.used(); ++index) { |
| 1626 SkDPoint oppPt = i.pt(index); |
| 1627 if (oppPt.approximatelyEqual(midPt)) { |
| 1628 SkVector oppDxdy = (*CurveSlopeAtT[oppPtCount])(opp-
>pts(), |
| 1629 i[index][0]); |
| 1630 oppDxdy.normalize(); |
| 1631 dxdy.normalize(); |
| 1632 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy)
/ FLT_EPSILON); |
| 1633 coincident |= flatness < 5000; // FIXME: replace wi
th tuned value |
| 1634 } |
| 1635 } |
| 1636 } |
| 1637 } |
| 1638 if (coincident) { |
| 1639 // mark coincidence |
| 1640 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator); |
| 1641 clear_visited(&fHead); |
| 1642 missingCoincidence(coincidences, allocator); |
| 1643 return; |
| 1644 } |
| 1645 swapBack: |
| 1646 if (swapped) { |
| 1647 SkTSwap(priorPtT, ptT); |
| 1648 } |
| 4415 } | 1649 } |
| 4416 } else { | 1650 } while ((span = span->next()->upCastable())); |
| 4417 while (fTs[from].fTiny) { | 1651 clear_visited(&fHead); |
| 4418 from++; | 1652 } |
| 1653 |
| 1654 // Move nearby t values and pts so they all hang off the same span. Alignment ha
ppens later. |
| 1655 bool SkOpSegment::moveNearby() { |
| 1656 debugValidate(); |
| 1657 SkOpSpanBase* spanS = &fHead; |
| 1658 do { |
| 1659 SkOpSpanBase* test = spanS->upCast()->next(); |
| 1660 SkOpSpanBase* next; |
| 1661 if (spanS->contains(test)) { |
| 1662 if (!test->final()) { |
| 1663 test->upCast()->detach(spanS->ptT()); |
| 1664 continue; |
| 1665 } else if (spanS != &fHead) { |
| 1666 spanS->upCast()->detach(test->ptT()); |
| 1667 spanS = test; |
| 1668 continue; |
| 1669 } |
| 4419 } | 1670 } |
| 4420 const SkOpSpan& fromSpan = fTs[from]; | 1671 do { // iterate through all spans associated with start |
| 4421 int count = fTs.count(); | 1672 SkOpPtT* startBase = spanS->ptT(); |
| 4422 while (++to < count) { | 1673 next = test->final() ? NULL : test->upCast()->next(); |
| 4423 const SkOpSpan& span = fTs[to]; | 1674 do { |
| 4424 if (precisely_negative(span.fT - fromSpan.fT)) { | 1675 SkOpPtT* testBase = test->ptT(); |
| 4425 continue; | 1676 do { |
| 4426 } | 1677 if (startBase == testBase) { |
| 4427 return to; | 1678 goto checkNextSpan; |
| 4428 } | 1679 } |
| 1680 if (testBase->duplicate()) { |
| 1681 continue; |
| 1682 } |
| 1683 if (this->match(startBase, testBase->segment(), testBase->fT
, testBase->fPt)) { |
| 1684 if (test == &this->fTail) { |
| 1685 if (spanS == &fHead) { |
| 1686 debugValidate(); |
| 1687 return true; // if this span has collapsed, rem
ove it from parent |
| 1688 } |
| 1689 this->fTail.merge(spanS->upCast()); |
| 1690 debugValidate(); |
| 1691 return true; |
| 1692 } |
| 1693 spanS->merge(test->upCast()); |
| 1694 spanS->upCast()->setNext(next); |
| 1695 goto checkNextSpan; |
| 1696 } |
| 1697 } while ((testBase = testBase->next()) != test->ptT()); |
| 1698 } while ((startBase = startBase->next()) != spanS->ptT()); |
| 1699 checkNextSpan: |
| 1700 ; |
| 1701 } while ((test = next)); |
| 1702 spanS = spanS->upCast()->next(); |
| 1703 } while (!spanS->final()); |
| 1704 debugValidate(); |
| 1705 return true; |
| 1706 } |
| 1707 |
| 1708 bool SkOpSegment::operand() const { |
| 1709 return fContour->operand(); |
| 1710 } |
| 1711 |
| 1712 bool SkOpSegment::oppXor() const { |
| 1713 return fContour->oppXor(); |
| 1714 } |
| 1715 |
| 1716 bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const Sk
Point& pt2) const { |
| 1717 if (fVerb == SkPath::kLine_Verb) { |
| 1718 return false; |
| 4429 } | 1719 } |
| 4430 return -1; | 1720 // quads (and cubics) can loop back to nearly a line so that an opposite cur
ve |
| 4431 } | 1721 // hits in two places with very different t values. |
| 4432 | 1722 // OPTIMIZATION: curves could be preflighted so that, for example, something
like |
| 4433 void SkOpSegment::pinT(const SkPoint& pt, double* t) { | 1723 // 'controls contained by ends' could avoid this check for common curves |
| 4434 if (pt == fPts[0]) { | 1724 // 'ends are extremes in x or y' is cheaper to compute and real-world common |
| 4435 *t = 0; | 1725 // on the other hand, the below check is relatively inexpensive |
| 4436 } | 1726 double midT = (t1 + t2) / 2; |
| 4437 int count = SkPathOpsVerbToPoints(fVerb); | 1727 SkPoint midPt = this->ptAtT(midT); |
| 4438 if (pt == fPts[count]) { | 1728 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2); |
| 4439 *t = 1; | 1729 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seD
istSq; |
| 4440 } | 1730 } |
| 4441 } | 1731 |
| 4442 | 1732 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
MiWinding, |
| 4443 bool SkOpSegment::reversePoints(const SkPoint& p1, const SkPoint& p2) const { | 1733 int* maxWinding, int* sumWinding) { |
| 4444 SkASSERT(p1 != p2); | 1734 int deltaSum = SpanSign(start, end); |
| 4445 int spanCount = count(); | 1735 *maxWinding = *sumMiWinding; |
| 4446 int p1IndexMin = -1; | 1736 *sumWinding = *sumMiWinding -= deltaSum; |
| 4447 int p2IndexMax = spanCount; | 1737 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); |
| 4448 for (int index = 0; index < spanCount; ++index) { | 1738 } |
| 4449 const SkOpSpan& span = fTs[index]; | 1739 |
| 4450 if (span.fPt == p1) { | 1740 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
MiWinding, |
| 4451 if (p1IndexMin < 0) { | 1741 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding, |
| 4452 p1IndexMin = index; | 1742 int* oppSumWinding) { |
| 4453 } | 1743 int deltaSum = SpanSign(start, end); |
| 4454 } else if (span.fPt == p2) { | 1744 int oppDeltaSum = OppSign(start, end); |
| 4455 p2IndexMax = index; | |
| 4456 } | |
| 4457 } | |
| 4458 return p1IndexMin > p2IndexMax; | |
| 4459 } | |
| 4460 | |
| 4461 void SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endP
t, | |
| 4462 SkOpSegment* other) { | |
| 4463 int count = this->count(); | |
| 4464 for (int index = 0; index < count; ++index) { | |
| 4465 SkOpSpan &span = fTs[index]; | |
| 4466 if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther)
{ | |
| 4467 span.fCoincident = true; | |
| 4468 } | |
| 4469 } | |
| 4470 } | |
| 4471 | |
| 4472 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int*
sumSuWinding, | |
| 4473 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding
) { | |
| 4474 int deltaSum = spanSign(index, endIndex); | |
| 4475 int oppDeltaSum = oppSign(index, endIndex); | |
| 4476 if (operand()) { | 1745 if (operand()) { |
| 4477 *maxWinding = *sumSuWinding; | 1746 *maxWinding = *sumSuWinding; |
| 4478 *sumWinding = *sumSuWinding -= deltaSum; | 1747 *sumWinding = *sumSuWinding -= deltaSum; |
| 4479 *oppMaxWinding = *sumMiWinding; | 1748 *oppMaxWinding = *sumMiWinding; |
| 4480 *oppSumWinding = *sumMiWinding -= oppDeltaSum; | 1749 *oppSumWinding = *sumMiWinding -= oppDeltaSum; |
| 4481 } else { | 1750 } else { |
| 4482 *maxWinding = *sumMiWinding; | 1751 *maxWinding = *sumMiWinding; |
| 4483 *sumWinding = *sumMiWinding -= deltaSum; | 1752 *sumWinding = *sumMiWinding -= deltaSum; |
| 4484 *oppMaxWinding = *sumSuWinding; | 1753 *oppMaxWinding = *sumSuWinding; |
| 4485 *oppSumWinding = *sumSuWinding -= oppDeltaSum; | 1754 *oppSumWinding = *sumSuWinding -= oppDeltaSum; |
| 4486 } | 1755 } |
| 4487 #if DEBUG_LIMIT_WIND_SUM | 1756 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); |
| 4488 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); | 1757 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SU
M); |
| 4489 SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); | |
| 4490 #endif | |
| 4491 } | |
| 4492 | |
| 4493 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, | |
| 4494 int* maxWinding, int* sumWinding) { | |
| 4495 int deltaSum = spanSign(index, endIndex); | |
| 4496 *maxWinding = *sumMiWinding; | |
| 4497 *sumWinding = *sumMiWinding -= deltaSum; | |
| 4498 #if DEBUG_LIMIT_WIND_SUM | |
| 4499 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); | |
| 4500 #endif | |
| 4501 } | 1758 } |
| 4502 | 1759 |
| 4503 void SkOpSegment::sortAngles() { | 1760 void SkOpSegment::sortAngles() { |
| 4504 int spanCount = fTs.count(); | 1761 SkOpSpanBase* span = &this->fHead; |
| 4505 if (spanCount <= 2) { | |
| 4506 return; | |
| 4507 } | |
| 4508 int index = 0; | |
| 4509 do { | 1762 do { |
| 4510 SkOpAngle* fromAngle = fTs[index].fFromAngle; | 1763 SkOpAngle* fromAngle = span->fromAngle(); |
| 4511 SkOpAngle* toAngle = fTs[index].fToAngle; | 1764 SkOpAngle* toAngle = span->final() ? NULL : span->upCast()->toAngle(); |
| 4512 if (!fromAngle && !toAngle) { | 1765 if (!fromAngle && !toAngle) { |
| 4513 index += 1; | |
| 4514 continue; | 1766 continue; |
| 4515 } | 1767 } |
| 4516 SkOpAngle* baseAngle = NULL; | |
| 4517 if (fromAngle) { | |
| 4518 baseAngle = fromAngle; | |
| 4519 if (inLoop(baseAngle, spanCount, &index)) { | |
| 4520 continue; | |
| 4521 } | |
| 4522 } | |
| 4523 #if DEBUG_ANGLE | 1768 #if DEBUG_ANGLE |
| 4524 bool wroteAfterHeader = false; | 1769 bool wroteAfterHeader = false; |
| 4525 #endif | 1770 #endif |
| 4526 if (toAngle) { | 1771 SkOpAngle* baseAngle = fromAngle; |
| 4527 if (!baseAngle) { | 1772 if (fromAngle && toAngle) { |
| 4528 baseAngle = toAngle; | |
| 4529 if (inLoop(baseAngle, spanCount, &index)) { | |
| 4530 continue; | |
| 4531 } | |
| 4532 } else { | |
| 4533 SkDEBUGCODE(int newIndex = index); | |
| 4534 SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex ==
index); | |
| 4535 #if DEBUG_ANGLE | 1773 #if DEBUG_ANGLE |
| 4536 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
fTs[index].fT, | 1774 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), spa
n->t(), |
| 4537 index); | 1775 span->debugID()); |
| 4538 wroteAfterHeader = true; | 1776 wroteAfterHeader = true; |
| 4539 #endif | 1777 #endif |
| 4540 baseAngle->insert(toAngle); | 1778 fromAngle->insert(toAngle); |
| 1779 } else if (!fromAngle) { |
| 1780 baseAngle = toAngle; |
| 1781 } |
| 1782 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; |
| 1783 do { |
| 1784 SkOpSpanBase* oSpan = ptT->span(); |
| 1785 if (oSpan == span) { |
| 1786 continue; |
| 4541 } | 1787 } |
| 4542 } | 1788 SkOpAngle* oAngle = oSpan->fromAngle(); |
| 4543 SkOpAngle* nextFrom, * nextTo; | |
| 4544 int firstIndex = index; | |
| 4545 do { | |
| 4546 SkOpSpan& span = fTs[index]; | |
| 4547 SkOpSegment* other = span.fOther; | |
| 4548 SkOpSpan& oSpan = other->fTs[span.fOtherIndex]; | |
| 4549 SkOpAngle* oAngle = oSpan.fFromAngle; | |
| 4550 if (oAngle) { | 1789 if (oAngle) { |
| 4551 #if DEBUG_ANGLE | 1790 #if DEBUG_ANGLE |
| 4552 if (!wroteAfterHeader) { | 1791 if (!wroteAfterHeader) { |
| 4553 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI
D(), fTs[index].fT, | 1792 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI
D(), |
| 4554 index); | 1793 span->t(), span->debugID()); |
| 4555 wroteAfterHeader = true; | 1794 wroteAfterHeader = true; |
| 4556 } | 1795 } |
| 4557 #endif | 1796 #endif |
| 4558 if (!oAngle->loopContains(*baseAngle)) { | 1797 if (!oAngle->loopContains(baseAngle)) { |
| 4559 baseAngle->insert(oAngle); | 1798 baseAngle->insert(oAngle); |
| 4560 } | 1799 } |
| 4561 } | 1800 } |
| 4562 oAngle = oSpan.fToAngle; | 1801 if (!oSpan->final()) { |
| 4563 if (oAngle) { | 1802 oAngle = oSpan->upCast()->toAngle(); |
| 1803 if (oAngle) { |
| 4564 #if DEBUG_ANGLE | 1804 #if DEBUG_ANGLE |
| 4565 if (!wroteAfterHeader) { | 1805 if (!wroteAfterHeader) { |
| 4566 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI
D(), fTs[index].fT, | 1806 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, de
bugID(), |
| 4567 index); | 1807 span->t(), span->debugID()); |
| 4568 wroteAfterHeader = true; | 1808 wroteAfterHeader = true; |
| 4569 } | 1809 } |
| 4570 #endif | 1810 #endif |
| 4571 if (!oAngle->loopContains(*baseAngle)) { | 1811 if (!oAngle->loopContains(baseAngle)) { |
| 4572 baseAngle->insert(oAngle); | 1812 baseAngle->insert(oAngle); |
| 1813 } |
| 4573 } | 1814 } |
| 4574 } | 1815 } |
| 4575 if (++index == spanCount) { | 1816 } while ((ptT = ptT->next()) != stopPtT); |
| 4576 break; | 1817 if (baseAngle->loopCount() == 1) { |
| 1818 span->setFromAngle(NULL); |
| 1819 if (toAngle) { |
| 1820 span->upCast()->setToAngle(NULL); |
| 4577 } | 1821 } |
| 4578 nextFrom = fTs[index].fFromAngle; | |
| 4579 nextTo = fTs[index].fToAngle; | |
| 4580 } while (fromAngle == nextFrom && toAngle == nextTo); | |
| 4581 if (baseAngle && baseAngle->loopCount() == 1) { | |
| 4582 index = firstIndex; | |
| 4583 do { | |
| 4584 SkOpSpan& span = fTs[index]; | |
| 4585 span.fFromAngle = span.fToAngle = NULL; | |
| 4586 if (++index == spanCount) { | |
| 4587 break; | |
| 4588 } | |
| 4589 nextFrom = fTs[index].fFromAngle; | |
| 4590 nextTo = fTs[index].fToAngle; | |
| 4591 } while (fromAngle == nextFrom && toAngle == nextTo); | |
| 4592 baseAngle = NULL; | 1822 baseAngle = NULL; |
| 4593 } | 1823 } |
| 4594 #if DEBUG_SORT | 1824 #if DEBUG_SORT |
| 4595 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); | 1825 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); |
| 4596 #endif | 1826 #endif |
| 4597 } while (index < spanCount); | 1827 } while (!span->final() && (span = span->upCast()->next())); |
| 4598 } | 1828 } |
| 4599 | 1829 |
| 4600 // return true if midpoints were computed | 1830 // return true if midpoints were computed |
| 4601 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { | 1831 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 1832 SkPoint edge[4]) const { |
| 4602 SkASSERT(start != end); | 1833 SkASSERT(start != end); |
| 4603 edge[0] = fTs[start].fPt; | 1834 const SkOpPtT& startPtT = *start->ptT(); |
| 1835 const SkOpPtT& endPtT = *end->ptT(); |
| 1836 edge[0] = startPtT.fPt; |
| 4604 int points = SkPathOpsVerbToPoints(fVerb); | 1837 int points = SkPathOpsVerbToPoints(fVerb); |
| 4605 edge[points] = fTs[end].fPt; | 1838 edge[points] = endPtT.fPt; |
| 4606 if (fVerb == SkPath::kLine_Verb) { | 1839 if (fVerb == SkPath::kLine_Verb) { |
| 4607 return false; | 1840 return false; |
| 4608 } | 1841 } |
| 4609 double startT = fTs[start].fT; | 1842 double startT = startPtT.fT; |
| 4610 double endT = fTs[end].fT; | 1843 double endT = endPtT.fT; |
| 4611 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { | 1844 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { |
| 4612 // don't compute midpoints if we already have them | 1845 // don't compute midpoints if we already have them |
| 4613 if (fVerb == SkPath::kQuad_Verb) { | 1846 if (fVerb == SkPath::kQuad_Verb) { |
| 4614 edge[1] = fPts[1]; | 1847 edge[1] = fPts[1]; |
| 4615 return false; | 1848 return false; |
| 4616 } | 1849 } |
| 4617 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1850 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 4618 if (start < end) { | 1851 if (start < end) { |
| 4619 edge[1] = fPts[1]; | 1852 edge[1] = fPts[1]; |
| 4620 edge[2] = fPts[2]; | 1853 edge[2] = fPts[2]; |
| 4621 return false; | 1854 return false; |
| 4622 } | 1855 } |
| 4623 edge[1] = fPts[2]; | 1856 edge[1] = fPts[2]; |
| 4624 edge[2] = fPts[1]; | 1857 edge[2] = fPts[1]; |
| 4625 return false; | 1858 return false; |
| 4626 } | 1859 } |
| 4627 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[p
oints].fY }}; | 1860 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[p
oints].fY }}; |
| 4628 if (fVerb == SkPath::kQuad_Verb) { | 1861 if (fVerb == SkPath::kQuad_Verb) { |
| 4629 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoi
nt(); | 1862 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoi
nt(); |
| 4630 } else { | 1863 } else { |
| 4631 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1864 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 4632 SkDPoint ctrl[2]; | 1865 SkDPoint ctrl[2]; |
| 4633 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); | 1866 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); |
| 4634 edge[1] = ctrl[0].asSkPoint(); | 1867 edge[1] = ctrl[0].asSkPoint(); |
| 4635 edge[2] = ctrl[1].asSkPoint(); | 1868 edge[2] = ctrl[1].asSkPoint(); |
| 4636 } | 1869 } |
| 4637 return true; | 1870 return true; |
| 4638 } | 1871 } |
| 4639 | 1872 |
| 4640 // return true if midpoints were computed | 1873 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 4641 bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const { | 1874 SkDCubic* result) const { |
| 4642 SkASSERT(start != end); | 1875 SkASSERT(start != end); |
| 4643 (*result)[0].set(fTs[start].fPt); | 1876 const SkOpPtT& startPtT = *start->ptT(); |
| 1877 const SkOpPtT& endPtT = *end->ptT(); |
| 1878 (*result)[0].set(startPtT.fPt); |
| 4644 int points = SkPathOpsVerbToPoints(fVerb); | 1879 int points = SkPathOpsVerbToPoints(fVerb); |
| 4645 (*result)[points].set(fTs[end].fPt); | 1880 (*result)[points].set(endPtT.fPt); |
| 4646 if (fVerb == SkPath::kLine_Verb) { | 1881 if (fVerb == SkPath::kLine_Verb) { |
| 4647 return false; | 1882 return false; |
| 4648 } | 1883 } |
| 4649 double startT = fTs[start].fT; | 1884 double startT = startPtT.fT; |
| 4650 double endT = fTs[end].fT; | 1885 double endT = endPtT.fT; |
| 4651 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { | 1886 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { |
| 4652 // don't compute midpoints if we already have them | 1887 // don't compute midpoints if we already have them |
| 4653 if (fVerb == SkPath::kQuad_Verb) { | 1888 if (fVerb == SkPath::kQuad_Verb) { |
| 4654 (*result)[1].set(fPts[1]); | 1889 (*result)[1].set(fPts[1]); |
| 4655 return false; | 1890 return false; |
| 4656 } | 1891 } |
| 4657 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1892 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 4658 if (start < end) { | 1893 if (startT == 0) { |
| 4659 (*result)[1].set(fPts[1]); | 1894 (*result)[1].set(fPts[1]); |
| 4660 (*result)[2].set(fPts[2]); | 1895 (*result)[2].set(fPts[2]); |
| 4661 return false; | 1896 return false; |
| 4662 } | 1897 } |
| 4663 (*result)[1].set(fPts[2]); | 1898 (*result)[1].set(fPts[2]); |
| 4664 (*result)[2].set(fPts[1]); | 1899 (*result)[2].set(fPts[1]); |
| 4665 return false; | 1900 return false; |
| 4666 } | 1901 } |
| 4667 if (fVerb == SkPath::kQuad_Verb) { | 1902 if (fVerb == SkPath::kQuad_Verb) { |
| 4668 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], star
tT, endT); | 1903 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], star
tT, endT); |
| 4669 } else { | 1904 } else { |
| 4670 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1905 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 4671 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*r
esult)[1]); | 1906 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*r
esult)[1]); |
| 4672 } | 1907 } |
| 4673 return true; | 1908 return true; |
| 4674 } | 1909 } |
| 4675 | 1910 |
| 4676 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) c
onst { | 1911 void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase*
end, |
| 1912 SkPathOpsBounds* bounds) const { |
| 4677 SkPoint edge[4]; | 1913 SkPoint edge[4]; |
| 4678 subDivide(start, end, edge); | 1914 subDivide(start, end, edge); |
| 4679 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); | 1915 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); |
| 4680 } | 1916 } |
| 4681 | 1917 |
| 4682 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const Sk
Point& endPt, | 1918 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { |
| 4683 const SkPoint& startPt) { | 1919 SkOpSpan* span = this->head(); |
| 4684 int outCount = outsidePts->count(); | 1920 do { |
| 4685 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) { | 1921 if (!span->done()) { |
| 4686 outsidePts->push_back(endPt); | 1922 break; |
| 4687 outsidePts->push_back(startPt); | 1923 } |
| 4688 } | 1924 } while ((span = span->next()->upCastable())); |
| 1925 SkASSERT(span); |
| 1926 *start = span; |
| 1927 *end = span->next(); |
| 4689 } | 1928 } |
| 4690 | 1929 |
| 4691 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin
t& startPt) { | 1930 int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase*
end) const { |
| 4692 int outCount = outsidePts->count(); | 1931 const SkOpSpan* lesser = start->starter(end); |
| 4693 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) { | 1932 int oppWinding = lesser->oppSum(); |
| 4694 outsidePts->push_back(startPt); | 1933 int oppSpanWinding = SkOpSegment::OppSign(start, end); |
| 4695 } | |
| 4696 } | |
| 4697 | |
| 4698 void SkOpSegment::undoneSpan(int* start, int* end) { | |
| 4699 int tCount = fTs.count(); | |
| 4700 int index; | |
| 4701 for (index = 0; index < tCount; ++index) { | |
| 4702 if (!fTs[index].fDone) { | |
| 4703 break; | |
| 4704 } | |
| 4705 } | |
| 4706 SkASSERT(index < tCount - 1); | |
| 4707 *start = index; | |
| 4708 double startT = fTs[index].fT; | |
| 4709 while (approximately_negative(fTs[++index].fT - startT)) | |
| 4710 SkASSERT(index < tCount); | |
| 4711 SkASSERT(index < tCount); | |
| 4712 *end = index; | |
| 4713 } | |
| 4714 | |
| 4715 int SkOpSegment::updateOppWinding(int index, int endIndex) const { | |
| 4716 int lesser = SkMin32(index, endIndex); | |
| 4717 int oppWinding = oppSum(lesser); | |
| 4718 int oppSpanWinding = oppSign(index, endIndex); | |
| 4719 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWindin
g) | 1934 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWindin
g) |
| 4720 && oppWinding != SK_MaxS32) { | 1935 && oppWinding != SK_MaxS32) { |
| 4721 oppWinding -= oppSpanWinding; | 1936 oppWinding -= oppSpanWinding; |
| 4722 } | 1937 } |
| 4723 return oppWinding; | 1938 return oppWinding; |
| 4724 } | 1939 } |
| 4725 | 1940 |
| 4726 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const { | 1941 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const { |
| 4727 int startIndex = angle->start(); | 1942 const SkOpSpanBase* startSpan = angle->start(); |
| 4728 int endIndex = angle->end(); | 1943 const SkOpSpanBase* endSpan = angle->end(); |
| 4729 return updateOppWinding(endIndex, startIndex); | 1944 return updateOppWinding(endSpan, startSpan); |
| 4730 } | 1945 } |
| 4731 | 1946 |
| 4732 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { | 1947 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { |
| 4733 int startIndex = angle->start(); | 1948 const SkOpSpanBase* startSpan = angle->start(); |
| 4734 int endIndex = angle->end(); | 1949 const SkOpSpanBase* endSpan = angle->end(); |
| 4735 return updateOppWinding(startIndex, endIndex); | 1950 return updateOppWinding(startSpan, endSpan); |
| 4736 } | 1951 } |
| 4737 | 1952 |
| 4738 int SkOpSegment::updateWinding(int index, int endIndex) const { | 1953 int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* en
d) const { |
| 4739 int lesser = SkMin32(index, endIndex); | 1954 const SkOpSpan* lesser = start->starter(end); |
| 4740 int winding = windSum(lesser); | 1955 int winding = lesser->windSum(); |
| 4741 if (winding == SK_MinS32) { | 1956 if (winding == SK_MinS32) { |
| 4742 return winding; | 1957 return winding; |
| 4743 } | 1958 } |
| 4744 int spanWinding = spanSign(index, endIndex); | 1959 int spanWinding = SkOpSegment::SpanSign(start, end); |
| 4745 if (winding && UseInnerWinding(winding - spanWinding, winding) | 1960 if (winding && UseInnerWinding(winding - spanWinding, winding) |
| 4746 && winding != SK_MaxS32) { | 1961 && winding != SK_MaxS32) { |
| 4747 winding -= spanWinding; | 1962 winding -= spanWinding; |
| 4748 } | 1963 } |
| 4749 return winding; | 1964 return winding; |
| 4750 } | 1965 } |
| 4751 | 1966 |
| 4752 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { | 1967 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { |
| 4753 int startIndex = angle->start(); | 1968 const SkOpSpanBase* startSpan = angle->start(); |
| 4754 int endIndex = angle->end(); | 1969 const SkOpSpanBase* endSpan = angle->end(); |
| 4755 return updateWinding(endIndex, startIndex); | 1970 return updateWinding(endSpan, startSpan); |
| 4756 } | |
| 4757 | |
| 4758 int SkOpSegment::updateWindingReverse(int index, int endIndex) const { | |
| 4759 int lesser = SkMin32(index, endIndex); | |
| 4760 int winding = windSum(lesser); | |
| 4761 int spanWinding = spanSign(endIndex, index); | |
| 4762 if (winding && UseInnerWindingReverse(winding - spanWinding, winding) | |
| 4763 && winding != SK_MaxS32) { | |
| 4764 winding -= spanWinding; | |
| 4765 } | |
| 4766 return winding; | |
| 4767 } | 1971 } |
| 4768 | 1972 |
| 4769 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { | 1973 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { |
| 4770 int startIndex = angle->start(); | 1974 const SkOpSpanBase* startSpan = angle->start(); |
| 4771 int endIndex = angle->end(); | 1975 const SkOpSpanBase* endSpan = angle->end(); |
| 4772 return updateWindingReverse(endIndex, startIndex); | 1976 return updateWinding(startSpan, endSpan); |
| 4773 } | 1977 } |
| 4774 | 1978 |
| 4775 // OPTIMIZATION: does the following also work, and is it any faster? | 1979 // OPTIMIZATION: does the following also work, and is it any faster? |
| 4776 // return outerWinding * innerWinding > 0 | 1980 // return outerWinding * innerWinding > 0 |
| 4777 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) <
0))) | 1981 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) <
0))) |
| 4778 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { | 1982 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { |
| 4779 SkASSERT(outerWinding != SK_MaxS32); | 1983 SkASSERT(outerWinding != SK_MaxS32); |
| 4780 SkASSERT(innerWinding != SK_MaxS32); | 1984 SkASSERT(innerWinding != SK_MaxS32); |
| 4781 int absOut = abs(outerWinding); | 1985 int absOut = abs(outerWinding); |
| 4782 int absIn = abs(innerWinding); | 1986 int absIn = abs(innerWinding); |
| 4783 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; | 1987 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; |
| 4784 return result; | 1988 return result; |
| 4785 } | 1989 } |
| 4786 | 1990 |
| 4787 bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) { | 1991 int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp, |
| 4788 SkASSERT(outerWinding != SK_MaxS32); | 1992 SkScalar* dx) const { |
| 4789 SkASSERT(innerWinding != SK_MaxS32); | 1993 if (approximately_zero(tHit - span->t())) { // if we hit the end of a span,
disregard |
| 4790 int absOut = abs(outerWinding); | |
| 4791 int absIn = abs(innerWinding); | |
| 4792 bool result = absOut == absIn ? true : absOut < absIn; | |
| 4793 return result; | |
| 4794 } | |
| 4795 | |
| 4796 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx
) const { | |
| 4797 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span,
disregard | |
| 4798 return SK_MinS32; | 1994 return SK_MinS32; |
| 4799 } | 1995 } |
| 4800 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); | 1996 int winding = crossOpp ? span->oppSum() : span->windSum(); |
| 4801 SkASSERT(winding != SK_MinS32); | 1997 SkASSERT(winding != SK_MinS32); |
| 4802 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); | 1998 int windVal = crossOpp ? span->oppValue() : span->windValue(); |
| 4803 #if DEBUG_WINDING_AT_T | 1999 #if DEBUG_WINDING_AT_T |
| 4804 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __
FUNCTION__, | 2000 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __
FUNCTION__, |
| 4805 debugID(), crossOpp, tHit, t(tIndex), winding, windVal); | 2001 debugID(), crossOpp, tHit, span->t(), winding, windVal); |
| 4806 #endif | 2002 #endif |
| 4807 // see if a + change in T results in a +/- change in X (compute x'(T)) | 2003 // see if a + change in T results in a +/- change in X (compute x'(T)) |
| 4808 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; | 2004 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; |
| 4809 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { | 2005 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { |
| 4810 *dx = fPts[2].fX - fPts[1].fX - *dx; | 2006 *dx = fPts[2].fX - fPts[1].fX - *dx; |
| 4811 } | 2007 } |
| 4812 if (*dx == 0) { | 2008 if (*dx == 0) { |
| 4813 #if DEBUG_WINDING_AT_T | 2009 #if DEBUG_WINDING_AT_T |
| 4814 SkDebugf(" dx=0 winding=SK_MinS32\n"); | 2010 SkDebugf(" dx=0 winding=SK_MinS32\n"); |
| 4815 #endif | 2011 #endif |
| 4816 return SK_MinS32; | 2012 return SK_MinS32; |
| 4817 } | 2013 } |
| 4818 if (windVal < 0) { // reverse sign if opp contour traveled in reverse | 2014 if (windVal < 0) { // reverse sign if opp contour traveled in reverse |
| 4819 *dx = -*dx; | 2015 *dx = -*dx; |
| 4820 } | 2016 } |
| 4821 if (winding * *dx > 0) { // if same signs, result is negative | 2017 if (winding * *dx > 0) { // if same signs, result is negative |
| 4822 winding += *dx > 0 ? -windVal : windVal; | 2018 winding += *dx > 0 ? -windVal : windVal; |
| 4823 } | 2019 } |
| 4824 #if DEBUG_WINDING_AT_T | 2020 #if DEBUG_WINDING_AT_T |
| 4825 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); | 2021 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); |
| 4826 #endif | 2022 #endif |
| 4827 return winding; | 2023 return winding; |
| 4828 } | 2024 } |
| 4829 | 2025 |
| 4830 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 2026 int SkOpSegment::windSum(const SkOpAngle* angle) const { |
| 4831 int start = angle->start(); | 2027 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); |
| 4832 int end = angle->end(); | 2028 return minSpan->windSum(); |
| 4833 int index = SkMin32(start, end); | |
| 4834 return windSum(index); | |
| 4835 } | 2029 } |
| 4836 | |
| 4837 void SkOpSegment::zeroSpan(SkOpSpan* span) { | |
| 4838 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); | |
| 4839 span->fWindValue = 0; | |
| 4840 span->fOppValue = 0; | |
| 4841 if (span->fTiny || span->fSmall) { | |
| 4842 return; | |
| 4843 } | |
| 4844 SkASSERT(!span->fDone); | |
| 4845 span->fDone = true; | |
| 4846 ++fDoneSpans; | |
| 4847 } | |
| OLD | NEW |