| 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 "SkIntersections.h" |
| 8 #include "SkOpSegment.h" | 8 #include "SkOpSegment.h" |
| 9 #include "SkPathWriter.h" | 9 #include "SkPathWriter.h" |
| 10 #include "SkTSort.h" | 10 #include "SkTSort.h" |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 bool to = *sumWinding != 0; | 202 bool to = *sumWinding != 0; |
| 203 bool result = gUnaryActiveEdge[from][to]; | 203 bool result = gUnaryActiveEdge[from][to]; |
| 204 return result; | 204 return result; |
| 205 } | 205 } |
| 206 | 206 |
| 207 void SkOpSegment::addAngle(SkTDArray<SkOpAngle>* anglesPtr, int start, int end)
const { | 207 void SkOpSegment::addAngle(SkTDArray<SkOpAngle>* anglesPtr, int start, int end)
const { |
| 208 SkASSERT(start != end); | 208 SkASSERT(start != end); |
| 209 SkOpAngle* angle = anglesPtr->append(); | 209 SkOpAngle* angle = anglesPtr->append(); |
| 210 #if DEBUG_ANGLE | 210 #if DEBUG_ANGLE |
| 211 SkTDArray<SkOpAngle>& angles = *anglesPtr; | 211 SkTDArray<SkOpAngle>& angles = *anglesPtr; |
| 212 if (angles.count() > 1 && !fTs[start].fTiny) { | 212 if (angles.count() > 1) { |
| 213 SkPoint angle0Pt = (*CurvePointAtT[SkPathOpsVerbToPoints(angles[0].verb(
))])(angles[0].pts(), | 213 const SkOpSegment* aSeg = angles[0].segment(); |
| 214 (*angles[0].spans())[angles[0].start()].fT); | 214 int aStart = angles[0].start(); |
| 215 SkPoint newPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs
[start].fT); | 215 if (!aSeg->fTs[aStart].fTiny) { |
| 216 bool match = AlmostEqualUlps(angle0Pt.fX, newPt.fX); | 216 const SkPoint& angle0Pt = aSeg->xyAtT(aStart); |
| 217 match &= AlmostEqualUlps(angle0Pt.fY, newPt.fY); | 217 SkDPoint newPt = (*CurveDPointAtT[SkPathOpsVerbToPoints(aSeg->fVerb)
])(aSeg->fPts, |
| 218 if (!match) { | 218 aSeg->fTs[aStart].fT); |
| 219 SkDebugf("%s no match\n", __FUNCTION__); | 219 #if ONE_OFF_DEBUG |
| 220 SkASSERT(0); | 220 SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g)\n", __FUNCTION__
, |
| 221 aSeg->fTs[aStart].fT, newPt.fX, newPt.fY, angle0Pt.fX, angle
0Pt.fY); |
| 222 #endif |
| 223 SkASSERT(newPt.approximatelyEqual(angle0Pt)); |
| 221 } | 224 } |
| 222 } | 225 } |
| 223 #endif | 226 #endif |
| 224 angle->set(fPts, fVerb, this, start, end, fTs); | 227 angle->set(this, start, end); |
| 225 } | 228 } |
| 226 | 229 |
| 227 void SkOpSegment::addCancelOutsides(double tStart, double oStart, SkOpSegment* o
ther, double oEnd) { | 230 void SkOpSegment::addCancelOutsides(double tStart, double oStart, SkOpSegment* o
ther, double oEnd) { |
| 228 int tIndex = -1; | 231 int tIndex = -1; |
| 229 int tCount = fTs.count(); | 232 int tCount = fTs.count(); |
| 230 int oIndex = -1; | 233 int oIndex = -1; |
| 231 int oCount = other->fTs.count(); | 234 int oCount = other->fTs.count(); |
| 232 do { | 235 do { |
| 233 ++tIndex; | 236 ++tIndex; |
| 234 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount
); | 237 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount
); |
| (...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 846 other->addTwoAngles(next, oIndex, angles); | 849 other->addTwoAngles(next, oIndex, angles); |
| 847 } | 850 } |
| 848 | 851 |
| 849 int SkOpSegment::computeSum(int startIndex, int endIndex, bool binary) { | 852 int SkOpSegment::computeSum(int startIndex, int endIndex, bool binary) { |
| 850 SkTDArray<SkOpAngle> angles; | 853 SkTDArray<SkOpAngle> angles; |
| 851 addTwoAngles(startIndex, endIndex, &angles); | 854 addTwoAngles(startIndex, endIndex, &angles); |
| 852 buildAngles(endIndex, &angles, false); | 855 buildAngles(endIndex, &angles, false); |
| 853 // OPTIMIZATION: check all angles to see if any have computed wind sum | 856 // OPTIMIZATION: check all angles to see if any have computed wind sum |
| 854 // before sorting (early exit if none) | 857 // before sorting (early exit if none) |
| 855 SkTDArray<SkOpAngle*> sorted; | 858 SkTDArray<SkOpAngle*> sorted; |
| 856 bool sortable = SortAngles(angles, &sorted); | 859 // FIXME?: Not sure if this sort must be ordered or if the relaxed ordering
is OK ... |
| 860 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); |
| 857 #if DEBUG_SORT | 861 #if DEBUG_SORT |
| 858 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0); | 862 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0); |
| 859 #endif | 863 #endif |
| 860 if (!sortable) { | 864 if (!sortable) { |
| 861 return SK_MinS32; | 865 return SK_MinS32; |
| 862 } | 866 } |
| 863 int angleCount = angles.count(); | 867 int angleCount = angles.count(); |
| 864 const SkOpAngle* angle; | 868 const SkOpAngle* angle; |
| 865 const SkOpSegment* base; | 869 const SkOpSegment* base; |
| 866 int winding; | 870 int winding; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 return bestTIndex; | 976 return bestTIndex; |
| 973 } | 977 } |
| 974 if (fBounds.fLeft == fBounds.fRight) { | 978 if (fBounds.fLeft == fBounds.fRight) { |
| 975 // if vertical, and directly above test point, wait for another one | 979 // if vertical, and directly above test point, wait for another one |
| 976 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTInde
x; | 980 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTInde
x; |
| 977 } | 981 } |
| 978 // intersect ray starting at basePt with edge | 982 // intersect ray starting at basePt with edge |
| 979 SkIntersections intersections; | 983 SkIntersections intersections; |
| 980 // OPTIMIZE: use specialty function that intersects ray with curve, | 984 // OPTIMIZE: use specialty function that intersects ray with curve, |
| 981 // returning t values only for curve (we don't care about t on ray) | 985 // returning t values only for curve (we don't care about t on ray) |
| 982 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])(fPts,
top, bottom, basePt.fX, false); | 986 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) |
| 987 (fPts, top, bottom, basePt.fX, false); |
| 983 if (pts == 0 || (current && pts == 1)) { | 988 if (pts == 0 || (current && pts == 1)) { |
| 984 return bestTIndex; | 989 return bestTIndex; |
| 985 } | 990 } |
| 986 if (current) { | 991 if (current) { |
| 987 SkASSERT(pts > 1); | 992 SkASSERT(pts > 1); |
| 988 int closestIdx = 0; | 993 int closestIdx = 0; |
| 989 double closest = fabs(intersections[0][0] - mid); | 994 double closest = fabs(intersections[0][0] - mid); |
| 990 for (int idx = 1; idx < pts; ++idx) { | 995 for (int idx = 1; idx < pts; ++idx) { |
| 991 double test = fabs(intersections[0][idx] - mid); | 996 double test = fabs(intersections[0][idx] - mid); |
| 992 if (closest > test) { | 997 if (closest > test) { |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 markDoneBinary(min); | 1124 markDoneBinary(min); |
| 1120 other = endSpan->fOther; | 1125 other = endSpan->fOther; |
| 1121 *nextStart = endSpan->fOtherIndex; | 1126 *nextStart = endSpan->fOtherIndex; |
| 1122 double startT = other->fTs[*nextStart].fT; | 1127 double startT = other->fTs[*nextStart].fT; |
| 1123 *nextEnd = *nextStart; | 1128 *nextEnd = *nextStart; |
| 1124 do { | 1129 do { |
| 1125 *nextEnd += step; | 1130 *nextEnd += step; |
| 1126 } | 1131 } |
| 1127 while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | 1132 while (precisely_zero(startT - other->fTs[*nextEnd].fT)); |
| 1128 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 1133 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
| 1134 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { |
| 1135 return NULL; |
| 1136 } |
| 1129 return other; | 1137 return other; |
| 1130 } | 1138 } |
| 1131 // more than one viable candidate -- measure angles to find best | 1139 // more than one viable candidate -- measure angles to find best |
| 1132 SkTDArray<SkOpAngle> angles; | 1140 SkTDArray<SkOpAngle> angles; |
| 1133 SkASSERT(startIndex - endIndex != 0); | 1141 SkASSERT(startIndex - endIndex != 0); |
| 1134 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1142 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
| 1135 addTwoAngles(startIndex, end, &angles); | 1143 addTwoAngles(startIndex, end, &angles); |
| 1136 buildAngles(end, &angles, true); | 1144 buildAngles(end, &angles, true); |
| 1137 SkTDArray<SkOpAngle*> sorted; | 1145 SkTDArray<SkOpAngle*> sorted; |
| 1138 bool sortable = SortAngles(angles, &sorted); | 1146 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); |
| 1139 int angleCount = angles.count(); | 1147 int angleCount = angles.count(); |
| 1140 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1148 int firstIndex = findStartingEdge(sorted, startIndex, end); |
| 1141 SkASSERT(firstIndex >= 0); | 1149 SkASSERT(firstIndex >= 0); |
| 1142 #if DEBUG_SORT | 1150 #if DEBUG_SORT |
| 1143 debugShowSort(__FUNCTION__, sorted, firstIndex); | 1151 debugShowSort(__FUNCTION__, sorted, firstIndex); |
| 1144 #endif | 1152 #endif |
| 1145 if (!sortable) { | 1153 if (!sortable) { |
| 1146 *unsortable = true; | 1154 *unsortable = true; |
| 1147 return NULL; | 1155 return NULL; |
| 1148 } | 1156 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1170 } | 1178 } |
| 1171 const SkOpAngle* nextAngle = sorted[nextIndex]; | 1179 const SkOpAngle* nextAngle = sorted[nextIndex]; |
| 1172 nextSegment = nextAngle->segment(); | 1180 nextSegment = nextAngle->segment(); |
| 1173 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | 1181 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; |
| 1174 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle
->start(), | 1182 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle
->start(), |
| 1175 nextAngle->end(), op, &sumMiWinding, &sumSuWinding, | 1183 nextAngle->end(), op, &sumMiWinding, &sumSuWinding, |
| 1176 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | 1184 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
| 1177 if (activeAngle) { | 1185 if (activeAngle) { |
| 1178 ++activeCount; | 1186 ++activeCount; |
| 1179 if (!foundAngle || (foundDone && activeCount & 1)) { | 1187 if (!foundAngle || (foundDone && activeCount & 1)) { |
| 1180 if (nextSegment->tiny(nextAngle)) { | 1188 if (nextSegment->isTiny(nextAngle)) { |
| 1181 *unsortable = true; | 1189 *unsortable = true; |
| 1182 return NULL; | 1190 return NULL; |
| 1183 } | 1191 } |
| 1184 foundAngle = nextAngle; | 1192 foundAngle = nextAngle; |
| 1185 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(n
extAngle); | 1193 foundDone = nextSegment->done(nextAngle) && !nextSegment->isTiny
(nextAngle); |
| 1186 } | 1194 } |
| 1187 } | 1195 } |
| 1188 if (nextSegment->done()) { | 1196 if (nextSegment->done()) { |
| 1189 continue; | 1197 continue; |
| 1190 } | 1198 } |
| 1191 if (nextSegment->windSum(nextAngle) != SK_MinS32) { | 1199 if (nextSegment->windSum(nextAngle) != SK_MinS32) { |
| 1192 continue; | 1200 continue; |
| 1193 } | 1201 } |
| 1194 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWi
nding, | 1202 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWi
nding, |
| 1195 oppSumWinding, activeAngle, nextAngle); | 1203 oppSumWinding, activeAngle, nextAngle); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 1258 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
| 1251 return other; | 1259 return other; |
| 1252 } | 1260 } |
| 1253 // more than one viable candidate -- measure angles to find best | 1261 // more than one viable candidate -- measure angles to find best |
| 1254 SkTDArray<SkOpAngle> angles; | 1262 SkTDArray<SkOpAngle> angles; |
| 1255 SkASSERT(startIndex - endIndex != 0); | 1263 SkASSERT(startIndex - endIndex != 0); |
| 1256 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1264 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
| 1257 addTwoAngles(startIndex, end, &angles); | 1265 addTwoAngles(startIndex, end, &angles); |
| 1258 buildAngles(end, &angles, true); | 1266 buildAngles(end, &angles, true); |
| 1259 SkTDArray<SkOpAngle*> sorted; | 1267 SkTDArray<SkOpAngle*> sorted; |
| 1260 bool sortable = SortAngles(angles, &sorted); | 1268 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); |
| 1261 int angleCount = angles.count(); | 1269 int angleCount = angles.count(); |
| 1262 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1270 int firstIndex = findStartingEdge(sorted, startIndex, end); |
| 1263 SkASSERT(firstIndex >= 0); | 1271 SkASSERT(firstIndex >= 0); |
| 1264 #if DEBUG_SORT | 1272 #if DEBUG_SORT |
| 1265 debugShowSort(__FUNCTION__, sorted, firstIndex); | 1273 debugShowSort(__FUNCTION__, sorted, firstIndex); |
| 1266 #endif | 1274 #endif |
| 1267 if (!sortable) { | 1275 if (!sortable) { |
| 1268 *unsortable = true; | 1276 *unsortable = true; |
| 1269 return NULL; | 1277 return NULL; |
| 1270 } | 1278 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1287 nextIndex = 0; | 1295 nextIndex = 0; |
| 1288 } | 1296 } |
| 1289 const SkOpAngle* nextAngle = sorted[nextIndex]; | 1297 const SkOpAngle* nextAngle = sorted[nextIndex]; |
| 1290 nextSegment = nextAngle->segment(); | 1298 nextSegment = nextAngle->segment(); |
| 1291 int maxWinding; | 1299 int maxWinding; |
| 1292 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn
gle->end(), | 1300 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn
gle->end(), |
| 1293 &maxWinding, &sumWinding); | 1301 &maxWinding, &sumWinding); |
| 1294 if (activeAngle) { | 1302 if (activeAngle) { |
| 1295 ++activeCount; | 1303 ++activeCount; |
| 1296 if (!foundAngle || (foundDone && activeCount & 1)) { | 1304 if (!foundAngle || (foundDone && activeCount & 1)) { |
| 1297 if (nextSegment->tiny(nextAngle)) { | 1305 if (nextSegment->isTiny(nextAngle)) { |
| 1298 *unsortable = true; | 1306 *unsortable = true; |
| 1299 return NULL; | 1307 return NULL; |
| 1300 } | 1308 } |
| 1301 foundAngle = nextAngle; | 1309 foundAngle = nextAngle; |
| 1302 foundDone = nextSegment->done(nextAngle); | 1310 foundDone = nextSegment->done(nextAngle); |
| 1303 } | 1311 } |
| 1304 } | 1312 } |
| 1305 if (nextSegment->done()) { | 1313 if (nextSegment->done()) { |
| 1306 continue; | 1314 continue; |
| 1307 } | 1315 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1379 } while (true); | 1387 } while (true); |
| 1380 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 1388 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
| 1381 return other; | 1389 return other; |
| 1382 } | 1390 } |
| 1383 SkTDArray<SkOpAngle> angles; | 1391 SkTDArray<SkOpAngle> angles; |
| 1384 SkASSERT(startIndex - endIndex != 0); | 1392 SkASSERT(startIndex - endIndex != 0); |
| 1385 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1393 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
| 1386 addTwoAngles(startIndex, end, &angles); | 1394 addTwoAngles(startIndex, end, &angles); |
| 1387 buildAngles(end, &angles, false); | 1395 buildAngles(end, &angles, false); |
| 1388 SkTDArray<SkOpAngle*> sorted; | 1396 SkTDArray<SkOpAngle*> sorted; |
| 1389 bool sortable = SortAngles(angles, &sorted); | 1397 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); |
| 1390 if (!sortable) { | 1398 if (!sortable) { |
| 1391 *unsortable = true; | 1399 *unsortable = true; |
| 1392 #if DEBUG_SORT | 1400 #if DEBUG_SORT |
| 1393 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex,
end), 0, 0); | 1401 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex,
end), 0, 0); |
| 1394 #endif | 1402 #endif |
| 1395 return NULL; | 1403 return NULL; |
| 1396 } | 1404 } |
| 1397 int angleCount = angles.count(); | 1405 int angleCount = angles.count(); |
| 1398 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1406 int firstIndex = findStartingEdge(sorted, startIndex, end); |
| 1399 SkASSERT(firstIndex >= 0); | 1407 SkASSERT(firstIndex >= 0); |
| 1400 #if DEBUG_SORT | 1408 #if DEBUG_SORT |
| 1401 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0); | 1409 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0); |
| 1402 #endif | 1410 #endif |
| 1403 SkASSERT(sorted[firstIndex]->segment() == this); | 1411 SkASSERT(sorted[firstIndex]->segment() == this); |
| 1404 int nextIndex = firstIndex + 1; | 1412 int nextIndex = firstIndex + 1; |
| 1405 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | 1413 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; |
| 1406 const SkOpAngle* foundAngle = NULL; | 1414 const SkOpAngle* foundAngle = NULL; |
| 1407 bool foundDone = false; | 1415 bool foundDone = false; |
| 1408 SkOpSegment* nextSegment; | 1416 SkOpSegment* nextSegment; |
| 1409 int activeCount = 0; | 1417 int activeCount = 0; |
| 1410 do { | 1418 do { |
| 1411 SkASSERT(nextIndex != firstIndex); | 1419 SkASSERT(nextIndex != firstIndex); |
| 1412 if (nextIndex == angleCount) { | 1420 if (nextIndex == angleCount) { |
| 1413 nextIndex = 0; | 1421 nextIndex = 0; |
| 1414 } | 1422 } |
| 1415 const SkOpAngle* nextAngle = sorted[nextIndex]; | 1423 const SkOpAngle* nextAngle = sorted[nextIndex]; |
| 1416 nextSegment = nextAngle->segment(); | 1424 nextSegment = nextAngle->segment(); |
| 1417 ++activeCount; | 1425 ++activeCount; |
| 1418 if (!foundAngle || (foundDone && activeCount & 1)) { | 1426 if (!foundAngle || (foundDone && activeCount & 1)) { |
| 1419 if (nextSegment->tiny(nextAngle)) { | 1427 if (nextSegment->isTiny(nextAngle)) { |
| 1420 *unsortable = true; | 1428 *unsortable = true; |
| 1421 return NULL; | 1429 return NULL; |
| 1422 } | 1430 } |
| 1423 foundAngle = nextAngle; | 1431 foundAngle = nextAngle; |
| 1424 foundDone = nextSegment->done(nextAngle); | 1432 foundDone = nextSegment->done(nextAngle); |
| 1425 } | 1433 } |
| 1426 if (nextSegment->done()) { | 1434 if (nextSegment->done()) { |
| 1427 continue; | 1435 continue; |
| 1428 } | 1436 } |
| 1429 } while (++nextIndex != lastIndex); | 1437 } while (++nextIndex != lastIndex); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1621 end = nextSpan(firstT, step); | 1629 end = nextSpan(firstT, step); |
| 1622 SkASSERT(end != -1); | 1630 SkASSERT(end != -1); |
| 1623 } | 1631 } |
| 1624 // if the topmost T is not on end, or is three-way or more, find left | 1632 // if the topmost T is not on end, or is three-way or more, find left |
| 1625 // look for left-ness from tLeft to firstT (matching y of other) | 1633 // look for left-ness from tLeft to firstT (matching y of other) |
| 1626 SkTDArray<SkOpAngle> angles; | 1634 SkTDArray<SkOpAngle> angles; |
| 1627 SkASSERT(firstT - end != 0); | 1635 SkASSERT(firstT - end != 0); |
| 1628 addTwoAngles(end, firstT, &angles); | 1636 addTwoAngles(end, firstT, &angles); |
| 1629 buildAngles(firstT, &angles, true); | 1637 buildAngles(firstT, &angles, true); |
| 1630 SkTDArray<SkOpAngle*> sorted; | 1638 SkTDArray<SkOpAngle*> sorted; |
| 1631 bool sortable = SortAngles(angles, &sorted); | 1639 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_Sor
tAngleKind); |
| 1632 int first = SK_MaxS32; | 1640 int first = SK_MaxS32; |
| 1633 SkScalar top = SK_ScalarMax; | 1641 SkScalar top = SK_ScalarMax; |
| 1634 int count = sorted.count(); | 1642 int count = sorted.count(); |
| 1635 for (int index = 0; index < count; ++index) { | 1643 for (int index = 0; index < count; ++index) { |
| 1636 const SkOpAngle* angle = sorted[index]; | 1644 const SkOpAngle* angle = sorted[index]; |
| 1637 SkOpSegment* next = angle->segment(); | 1645 SkOpSegment* next = angle->segment(); |
| 1638 SkPathOpsBounds bounds; | 1646 SkPathOpsBounds bounds; |
| 1639 next->subDivideBounds(angle->end(), angle->start(), &bounds); | 1647 next->subDivideBounds(angle->end(), angle->start(), &bounds); |
| 1640 if (approximately_greater(top, bounds.fTop)) { | 1648 if (approximately_greater(top, bounds.fTop)) { |
| 1641 top = bounds.fTop; | 1649 top = bounds.fTop; |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2074 #endif | 2082 #endif |
| 2075 span.fOppSum = oppWinding; | 2083 span.fOppSum = oppWinding; |
| 2076 return &span; | 2084 return &span; |
| 2077 } | 2085 } |
| 2078 | 2086 |
| 2079 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 2087 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
| 2080 bool SkOpSegment::clockwise(int tStart, int tEnd) const { | 2088 bool SkOpSegment::clockwise(int tStart, int tEnd) const { |
| 2081 SkASSERT(fVerb != SkPath::kLine_Verb); | 2089 SkASSERT(fVerb != SkPath::kLine_Verb); |
| 2082 SkPoint edge[4]; | 2090 SkPoint edge[4]; |
| 2083 subDivide(tStart, tEnd, edge); | 2091 subDivide(tStart, tEnd, edge); |
| 2084 double sum = (edge[0].fX - edge[SkPathOpsVerbToPoints(fVerb)].fX) * (edge[0]
.fY + edge[SkPathOpsVerbToPoints(fVerb)].fY); | 2092 int points = SkPathOpsVerbToPoints(fVerb); |
| 2093 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; |
| 2085 if (fVerb == SkPath::kCubic_Verb) { | 2094 if (fVerb == SkPath::kCubic_Verb) { |
| 2086 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); | 2095 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); |
| 2087 if (edge[1].fY < lesser && edge[2].fY < lesser) { | 2096 if (edge[1].fY < lesser && edge[2].fY < lesser) { |
| 2088 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1]
.fY} }}; | 2097 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1]
.fY} }}; |
| 2089 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3]
.fY} }}; | 2098 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3]
.fY} }}; |
| 2090 if (SkIntersections::Test(tangent1, tangent2)) { | 2099 if (SkIntersections::Test(tangent1, tangent2)) { |
| 2091 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); | 2100 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); |
| 2092 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); | 2101 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); |
| 2093 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); | 2102 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); |
| 2094 return sum <= 0; | 2103 return sum <= 0; |
| 2095 } | 2104 } |
| 2096 } | 2105 } |
| 2097 } | 2106 } |
| 2098 for (int idx = 0; idx < SkPathOpsVerbToPoints(fVerb); ++idx){ | 2107 for (int idx = 0; idx < points; ++idx){ |
| 2099 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx]
.fY); | 2108 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx]
.fY); |
| 2100 } | 2109 } |
| 2101 return sum <= 0; | 2110 return sum <= 0; |
| 2102 } | 2111 } |
| 2103 | 2112 |
| 2104 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { | 2113 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { |
| 2105 if (fVerb == SkPath::kLine_Verb) { | 2114 if (fVerb == SkPath::kLine_Verb) { |
| 2106 return false; | 2115 return false; |
| 2107 } | 2116 } |
| 2108 if (fVerb == SkPath::kQuad_Verb) { | 2117 if (fVerb == SkPath::kQuad_Verb) { |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2327 *sumWinding = *sumMiWinding -= deltaSum; | 2336 *sumWinding = *sumMiWinding -= deltaSum; |
| 2328 *oppMaxWinding = *sumSuWinding; | 2337 *oppMaxWinding = *sumSuWinding; |
| 2329 *oppSumWinding = *sumSuWinding -= oppDeltaSum; | 2338 *oppSumWinding = *sumSuWinding -= oppDeltaSum; |
| 2330 } | 2339 } |
| 2331 } | 2340 } |
| 2332 | 2341 |
| 2333 // This marks all spans unsortable so that this info is available for early | 2342 // This marks all spans unsortable so that this info is available for early |
| 2334 // exclusion in find top and others. This could be optimized to only mark | 2343 // exclusion in find top and others. This could be optimized to only mark |
| 2335 // adjacent spans that unsortable. However, this makes it difficult to later | 2344 // adjacent spans that unsortable. However, this makes it difficult to later |
| 2336 // determine starting points for edge detection in find top and the like. | 2345 // determine starting points for edge detection in find top and the like. |
| 2337 bool SkOpSegment::SortAngles(const SkTDArray<SkOpAngle>& angles, | 2346 bool SkOpSegment::SortAngles(const SkTDArray<SkOpAngle>& angles, SkTDArray<SkOpA
ngle*>* angleList, |
| 2338 SkTDArray<SkOpAngle*>* angleList) { | 2347 SortAngleKind orderKind) { |
| 2339 bool sortable = true; | 2348 bool sortable = true; |
| 2340 int angleCount = angles.count(); | 2349 int angleCount = angles.count(); |
| 2341 int angleIndex; | 2350 int angleIndex; |
| 2342 angleList->setReserve(angleCount); | 2351 angleList->setReserve(angleCount); |
| 2343 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2352 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
| 2344 const SkOpAngle& angle = angles[angleIndex]; | 2353 const SkOpAngle& angle = angles[angleIndex]; |
| 2345 *angleList->append() = const_cast<SkOpAngle*>(&angle); | 2354 *angleList->append() = const_cast<SkOpAngle*>(&angle); |
| 2346 sortable &= !angle.unsortable(); | 2355 #if DEBUG_ANGLE |
| 2356 (*(angleList->end() - 1))->setID(angleIndex); |
| 2357 #endif |
| 2358 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAng
leKind |
| 2359 && angle.unorderable())); |
| 2347 } | 2360 } |
| 2348 if (sortable) { | 2361 if (sortable) { |
| 2349 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); | 2362 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); |
| 2350 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2363 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
| 2351 if (angles[angleIndex].unsortable()) { | 2364 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_
SortAngleKind |
| 2365 && angles[angleIndex].unorderable())) { |
| 2352 sortable = false; | 2366 sortable = false; |
| 2353 break; | 2367 break; |
| 2354 } | 2368 } |
| 2355 } | 2369 } |
| 2356 } | 2370 } |
| 2357 if (!sortable) { | 2371 if (!sortable) { |
| 2358 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2372 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
| 2359 const SkOpAngle& angle = angles[angleIndex]; | 2373 const SkOpAngle& angle = angles[angleIndex]; |
| 2360 angle.segment()->markUnsortable(angle.start(), angle.end()); | 2374 angle.segment()->markUnsortable(angle.start(), angle.end()); |
| 2361 } | 2375 } |
| 2362 } | 2376 } |
| 2363 return sortable; | 2377 return sortable; |
| 2364 } | 2378 } |
| 2365 | 2379 |
| 2366 void SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { | 2380 // return true if midpoints were computed |
| 2381 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { |
| 2382 SkASSERT(start != end); |
| 2367 edge[0] = fTs[start].fPt; | 2383 edge[0] = fTs[start].fPt; |
| 2368 edge[SkPathOpsVerbToPoints(fVerb)] = fTs[end].fPt; | 2384 int points = SkPathOpsVerbToPoints(fVerb); |
| 2369 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) { | 2385 edge[points] = fTs[end].fPt; |
| 2370 SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[SkPathOpsVerbToPoint
s(fVerb)].fX, edge[SkPathOpsVerbToPoints(fVerb)].fY }}; | 2386 if (fVerb == SkPath::kLine_Verb) { |
| 2387 return false; |
| 2388 } |
| 2389 double startT = fTs[start].fT; |
| 2390 double endT = fTs[end].fT; |
| 2391 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { |
| 2392 // don't compute midpoints if we already have them |
| 2371 if (fVerb == SkPath::kQuad_Verb) { | 2393 if (fVerb == SkPath::kQuad_Verb) { |
| 2372 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], fTs[start].fT, | 2394 edge[1] = fPts[1]; |
| 2373 fTs[end].fT).asSkPoint(); | 2395 return false; |
| 2374 } else { | |
| 2375 SkDCubic::SubDivide(fPts, sub[0], sub[1], fTs[start].fT, fTs[end].fT
, sub); | |
| 2376 edge[1] = sub[0].asSkPoint(); | |
| 2377 edge[2] = sub[1].asSkPoint(); | |
| 2378 } | 2396 } |
| 2397 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 2398 if (start < end) { |
| 2399 edge[1] = fPts[1]; |
| 2400 edge[2] = fPts[2]; |
| 2401 return false; |
| 2402 } |
| 2403 edge[1] = fPts[2]; |
| 2404 edge[2] = fPts[1]; |
| 2405 return false; |
| 2379 } | 2406 } |
| 2407 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[p
oints].fY }}; |
| 2408 if (fVerb == SkPath::kQuad_Verb) { |
| 2409 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoi
nt(); |
| 2410 } else { |
| 2411 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 2412 SkDPoint ctrl[2]; |
| 2413 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); |
| 2414 edge[1] = ctrl[0].asSkPoint(); |
| 2415 edge[2] = ctrl[1].asSkPoint(); |
| 2416 } |
| 2417 return true; |
| 2418 } |
| 2419 |
| 2420 // return true if midpoints were computed |
| 2421 bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const { |
| 2422 SkASSERT(start != end); |
| 2423 (*result)[0].set(fTs[start].fPt); |
| 2424 int points = SkPathOpsVerbToPoints(fVerb); |
| 2425 (*result)[points].set(fTs[end].fPt); |
| 2426 if (fVerb == SkPath::kLine_Verb) { |
| 2427 return false; |
| 2428 } |
| 2429 double startT = fTs[start].fT; |
| 2430 double endT = fTs[end].fT; |
| 2431 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { |
| 2432 // don't compute midpoints if we already have them |
| 2433 if (fVerb == SkPath::kQuad_Verb) { |
| 2434 (*result)[1].set(fPts[1]); |
| 2435 return false; |
| 2436 } |
| 2437 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 2438 if (start < end) { |
| 2439 (*result)[1].set(fPts[1]); |
| 2440 (*result)[2].set(fPts[2]); |
| 2441 return false; |
| 2442 } |
| 2443 (*result)[1].set(fPts[2]); |
| 2444 (*result)[2].set(fPts[1]); |
| 2445 return false; |
| 2446 } |
| 2447 if (fVerb == SkPath::kQuad_Verb) { |
| 2448 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], star
tT, endT); |
| 2449 } else { |
| 2450 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 2451 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*r
esult)[1]); |
| 2452 } |
| 2453 return true; |
| 2380 } | 2454 } |
| 2381 | 2455 |
| 2382 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) c
onst { | 2456 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) c
onst { |
| 2383 SkPoint edge[4]; | 2457 SkPoint edge[4]; |
| 2384 subDivide(start, end, edge); | 2458 subDivide(start, end, edge); |
| 2385 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); | 2459 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); |
| 2386 } | 2460 } |
| 2387 | 2461 |
| 2388 bool SkOpSegment::tiny(const SkOpAngle* angle) const { | 2462 bool SkOpSegment::isTiny(const SkOpAngle* angle) const { |
| 2389 int start = angle->start(); | 2463 int start = angle->start(); |
| 2390 int end = angle->end(); | 2464 int end = angle->end(); |
| 2391 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; | 2465 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; |
| 2392 return mSpan.fTiny; | 2466 return mSpan.fTiny; |
| 2393 } | 2467 } |
| 2394 | 2468 |
| 2469 bool SkOpSegment::isTiny(int index) const { |
| 2470 return fTs[index].fTiny; |
| 2471 } |
| 2472 |
| 2395 void SkOpSegment::TrackOutside(SkTDArray<double>* outsideTs, double end, double
start) { | 2473 void SkOpSegment::TrackOutside(SkTDArray<double>* outsideTs, double end, double
start) { |
| 2396 int outCount = outsideTs->count(); | 2474 int outCount = outsideTs->count(); |
| 2397 if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2
])) { | 2475 if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2
])) { |
| 2398 *outsideTs->append() = end; | 2476 *outsideTs->append() = end; |
| 2399 *outsideTs->append() = start; | 2477 *outsideTs->append() = start; |
| 2400 } | 2478 } |
| 2401 } | 2479 } |
| 2402 | 2480 |
| 2403 void SkOpSegment::undoneSpan(int* start, int* end) { | 2481 void SkOpSegment::undoneSpan(int* start, int* end) { |
| 2404 size_t tCount = fTs.count(); | 2482 size_t tCount = fTs.count(); |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2728 lastSum = windSum; | 2806 lastSum = windSum; |
| 2729 windSum -= segment.spanSign(&angle); | 2807 windSum -= segment.spanSign(&angle); |
| 2730 if (oppoSign) { | 2808 if (oppoSign) { |
| 2731 oppLastSum = oppWindSum; | 2809 oppLastSum = oppWindSum; |
| 2732 oppWindSum -= oppoSign; | 2810 oppWindSum -= oppoSign; |
| 2733 } | 2811 } |
| 2734 } | 2812 } |
| 2735 } | 2813 } |
| 2736 SkDebugf("%s [%d] %s", __FUNCTION__, index, | 2814 SkDebugf("%s [%d] %s", __FUNCTION__, index, |
| 2737 angle.unsortable() ? "*** UNSORTABLE *** " : ""); | 2815 angle.unsortable() ? "*** UNSORTABLE *** " : ""); |
| 2738 #if COMPACT_DEBUG_SORT | 2816 #if DEBUG_SORT_COMPACT |
| 2739 SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)", | 2817 SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)", |
| 2740 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)], | 2818 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)], |
| 2741 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end, | 2819 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end, |
| 2742 segment.xAtT(&eSpan), segment.yAtT(&eSpan)); | 2820 segment.xAtT(&eSpan), segment.yAtT(&eSpan)); |
| 2743 #else | 2821 #else |
| 2744 switch (segment.fVerb) { | 2822 switch (segment.fVerb) { |
| 2745 case SkPath::kLine_Verb: | 2823 case SkPath::kLine_Verb: |
| 2746 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts)); | 2824 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts)); |
| 2747 break; | 2825 break; |
| 2748 case SkPath::kQuad_Verb: | 2826 case SkPath::kQuad_Verb: |
| 2749 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts)); | 2827 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts)); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2820 sum += fTs[i].fWindValue; | 2898 sum += fTs[i].fWindValue; |
| 2821 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); | 2899 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); |
| 2822 sum += fTs[i].fOppValue; | 2900 sum += fTs[i].fOppValue; |
| 2823 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); | 2901 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); |
| 2824 } | 2902 } |
| 2825 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, | 2903 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, |
| 2826 slots.begin() + slotCount); | 2904 slots.begin() + slotCount); |
| 2827 return sum; | 2905 return sum; |
| 2828 } | 2906 } |
| 2829 #endif | 2907 #endif |
| OLD | NEW |