| 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 "SkOpCoincidence.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" |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 } | 115 } |
| 116 { | 116 { |
| 117 const SkPoint& xy = span->pt(); | 117 const SkPoint& xy = span->pt(); |
| 118 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)) { |
| 119 topPt = xy; | 119 topPt = xy; |
| 120 if (firstSpan) { | 120 if (firstSpan) { |
| 121 *firstSpan = span; | 121 *firstSpan = span; |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 if (fVerb != SkPath::kLine_Verb && !lastDone) { | 124 if (fVerb != SkPath::kLine_Verb && !lastDone) { |
| 125 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPt
s, lastT, | 125 SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastT, span
->t()); |
| 126 span->t()); | |
| 127 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY | 126 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY |
| 128 && topPt.fX > curveTop.fX)) { | 127 && topPt.fX > curveTop.fX)) { |
| 129 topPt = curveTop; | 128 topPt = curveTop; |
| 130 if (firstSpan) { | 129 if (firstSpan) { |
| 131 *firstSpan = span; | 130 *firstSpan = span; |
| 132 } | 131 } |
| 133 } | 132 } |
| 134 } | 133 } |
| 135 lastT = span->t(); | 134 lastT = span->t(); |
| 136 } | 135 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 int maxWinding; | 194 int maxWinding; |
| 196 setUpWinding(start, end, &maxWinding, sumWinding); | 195 setUpWinding(start, end, &maxWinding, sumWinding); |
| 197 bool from = maxWinding != 0; | 196 bool from = maxWinding != 0; |
| 198 bool to = *sumWinding != 0; | 197 bool to = *sumWinding != 0; |
| 199 bool result = gUnaryActiveEdge[from][to]; | 198 bool result = gUnaryActiveEdge[from][to]; |
| 200 return result; | 199 return result; |
| 201 } | 200 } |
| 202 | 201 |
| 203 void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, | 202 void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 204 SkPathWriter* path, bool active) const { | 203 SkPathWriter* path, bool active) const { |
| 205 SkPoint edge[4]; | 204 SkOpCurve edge; |
| 206 const SkPoint* ePtr; | 205 const SkPoint* ePtr; |
| 206 SkScalar eWeight; |
| 207 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
) { | 207 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)
) { |
| 208 ePtr = fPts; | 208 ePtr = fPts; |
| 209 eWeight = fWeight; |
| 209 } else { | 210 } else { |
| 210 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) | 211 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) |
| 211 subDivide(start, end, edge); | 212 subDivide(start, end, &edge); |
| 212 ePtr = edge; | 213 ePtr = edge.fPts; |
| 214 eWeight = edge.fWeight; |
| 213 } | 215 } |
| 214 if (active) { | 216 if (active) { |
| 215 bool reverse = ePtr == fPts && start != &fHead; | 217 bool reverse = ePtr == fPts && start != &fHead; |
| 216 if (reverse) { | 218 if (reverse) { |
| 217 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); | 219 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); |
| 218 switch (fVerb) { | 220 switch (fVerb) { |
| 219 case SkPath::kLine_Verb: | 221 case SkPath::kLine_Verb: |
| 220 path->deferredLine(ePtr[0]); | 222 path->deferredLine(ePtr[0]); |
| 221 break; | 223 break; |
| 222 case SkPath::kQuad_Verb: | 224 case SkPath::kQuad_Verb: |
| 223 path->quadTo(ePtr[1], ePtr[0]); | 225 path->quadTo(ePtr[1], ePtr[0]); |
| 224 break; | 226 break; |
| 227 case SkPath::kConic_Verb: |
| 228 path->conicTo(ePtr[1], ePtr[0], eWeight); |
| 229 break; |
| 225 case SkPath::kCubic_Verb: | 230 case SkPath::kCubic_Verb: |
| 226 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]); | 231 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]); |
| 227 break; | 232 break; |
| 228 default: | 233 default: |
| 229 SkASSERT(0); | 234 SkASSERT(0); |
| 230 } | 235 } |
| 231 } else { | 236 } else { |
| 232 path->deferredMoveLine(ePtr[0]); | 237 path->deferredMoveLine(ePtr[0]); |
| 233 switch (fVerb) { | 238 switch (fVerb) { |
| 234 case SkPath::kLine_Verb: | 239 case SkPath::kLine_Verb: |
| 235 path->deferredLine(ePtr[1]); | 240 path->deferredLine(ePtr[1]); |
| 236 break; | 241 break; |
| 237 case SkPath::kQuad_Verb: | 242 case SkPath::kQuad_Verb: |
| 238 path->quadTo(ePtr[1], ePtr[2]); | 243 path->quadTo(ePtr[1], ePtr[2]); |
| 239 break; | 244 break; |
| 245 case SkPath::kConic_Verb: |
| 246 path->conicTo(ePtr[1], ePtr[2], eWeight); |
| 247 break; |
| 240 case SkPath::kCubic_Verb: | 248 case SkPath::kCubic_Verb: |
| 241 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); | 249 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); |
| 242 break; | 250 break; |
| 243 default: | 251 default: |
| 244 SkASSERT(0); | 252 SkASSERT(0); |
| 245 } | 253 } |
| 246 } | 254 } |
| 247 } | 255 } |
| 248 } | 256 } |
| 249 | 257 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 angle = span->toAngle(); | 477 angle = span->toAngle(); |
| 470 if (angle && angle->fCheckCoincidence) { | 478 if (angle && angle->fCheckCoincidence) { |
| 471 angle->checkNearCoincidence(); | 479 angle->checkNearCoincidence(); |
| 472 } | 480 } |
| 473 } while ((base = span->next())); | 481 } while ((base = span->next())); |
| 474 } | 482 } |
| 475 | 483 |
| 476 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 484 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
| 477 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
bool* swap) const { | 485 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
bool* swap) const { |
| 478 SkASSERT(fVerb != SkPath::kLine_Verb); | 486 SkASSERT(fVerb != SkPath::kLine_Verb); |
| 479 SkPoint edge[4]; | 487 SkOpCurve edge; |
| 480 if (fVerb == SkPath::kCubic_Verb) { | 488 if (fVerb == SkPath::kCubic_Verb) { |
| 481 double startT = start->t(); | 489 double startT = start->t(); |
| 482 double endT = end->t(); | 490 double endT = end->t(); |
| 483 bool flip = startT > endT; | 491 bool flip = startT > endT; |
| 484 SkDCubic cubic; | 492 SkDCubic cubic; |
| 485 cubic.set(fPts); | 493 cubic.set(fPts); |
| 486 double inflectionTs[2]; | 494 double inflectionTs[2]; |
| 487 int inflections = cubic.findInflections(inflectionTs); | 495 int inflections = cubic.findInflections(inflectionTs); |
| 488 for (int index = 0; index < inflections; ++index) { | 496 for (int index = 0; index < inflections; ++index) { |
| 489 double inflectionT = inflectionTs[index]; | 497 double inflectionT = inflectionTs[index]; |
| 490 if (between(startT, inflectionT, endT)) { | 498 if (between(startT, inflectionT, endT)) { |
| 491 if (flip) { | 499 if (flip) { |
| 492 if (inflectionT != endT) { | 500 if (!roughly_equal(inflectionT, endT)) { |
| 493 startT = inflectionT; | 501 startT = inflectionT; |
| 494 } | 502 } |
| 495 } else { | 503 } else { |
| 496 if (inflectionT != startT) { | 504 if (!roughly_equal(inflectionT, startT)) { |
| 497 endT = inflectionT; | 505 endT = inflectionT; |
| 498 } | 506 } |
| 499 } | 507 } |
| 500 } | 508 } |
| 501 } | 509 } |
| 502 SkDCubic part = cubic.subDivide(startT, endT); | 510 SkDCubic part = cubic.subDivide(startT, endT); |
| 503 for (int index = 0; index < 4; ++index) { | 511 edge.set(part); |
| 504 edge[index] = part[index].asSkPoint(); | |
| 505 } | |
| 506 } else { | 512 } else { |
| 507 subDivide(start, end, edge); | 513 subDivide(start, end, &edge); |
| 508 } | 514 } |
| 509 bool sumSet = false; | 515 bool sumSet = false; |
| 510 int points = SkPathOpsVerbToPoints(fVerb); | 516 int points = SkPathOpsVerbToPoints(fVerb); |
| 511 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; | 517 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; |
| 512 if (!sumSet) { | 518 if (!sumSet) { |
| 513 for (int idx = 0; idx < points; ++idx){ | 519 for (int idx = 0; idx < points; ++idx){ |
| 514 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[
idx].fY); | 520 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[
idx].fY); |
| 515 } | 521 } |
| 516 } | 522 } |
| 517 if (fVerb == SkPath::kCubic_Verb) { | 523 if (fVerb == SkPath::kCubic_Verb) { |
| 518 SkDCubic cubic; | 524 SkDCubic cubic; |
| 519 cubic.set(edge); | 525 cubic.set(edge.fPts); |
| 520 *swap = sum > 0 && !cubic.monotonicInY(); | 526 *swap = sum > 0 && !cubic.monotonicInY(); |
| 521 } else { | 527 } else { |
| 522 SkDQuad quad; | 528 SkDQuad quad; |
| 523 quad.set(edge); | 529 quad.set(edge.fPts); |
| 524 *swap = sum > 0 && !quad.monotonicInY(); | 530 *swap = sum > 0 && !quad.monotonicInY(); |
| 525 } | 531 } |
| 526 return sum <= 0; | 532 return sum <= 0; |
| 527 } | 533 } |
| 528 | 534 |
| 529 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, | 535 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
| 530 SkOpAngle::IncludeType includeType) { | 536 SkOpAngle::IncludeType includeType) { |
| 531 const SkOpSegment* baseSegment = baseAngle->segment(); | 537 const SkOpSegment* baseSegment = baseAngle->segment(); |
| 532 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 538 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
| 533 int sumSuWinding; | 539 int sumSuWinding; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 if (fBounds.fLeft == fBounds.fRight) { | 681 if (fBounds.fLeft == fBounds.fRight) { |
| 676 // if vertical, and directly above test point, wait for another one | 682 // if vertical, and directly above test point, wait for another one |
| 677 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft); | 683 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft); |
| 678 return NULL; | 684 return NULL; |
| 679 } | 685 } |
| 680 // intersect ray starting at basePt with edge | 686 // intersect ray starting at basePt with edge |
| 681 SkIntersections intersections; | 687 SkIntersections intersections; |
| 682 // OPTIMIZE: use specialty function that intersects ray with curve, | 688 // OPTIMIZE: use specialty function that intersects ray with curve, |
| 683 // returning t values only for curve (we don't care about t on ray) | 689 // returning t values only for curve (we don't care about t on ray) |
| 684 intersections.allowNear(false); | 690 intersections.allowNear(false); |
| 685 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) | 691 int pts = (intersections.*CurveVertical[fVerb])(fPts, fWeight, top, bottom,
basePt.fX, false); |
| 686 (fPts, top, bottom, basePt.fX, false); | |
| 687 if (pts == 0 || (current && pts == 1)) { | 692 if (pts == 0 || (current && pts == 1)) { |
| 688 return NULL; | 693 return NULL; |
| 689 } | 694 } |
| 690 if (current) { | 695 if (current) { |
| 691 SkASSERT(pts > 1); | 696 SkASSERT(pts > 1); |
| 692 int closestIdx = 0; | 697 int closestIdx = 0; |
| 693 double closest = fabs(intersections[0][0] - mid); | 698 double closest = fabs(intersections[0][0] - mid); |
| 694 for (int idx = 1; idx < pts; ++idx) { | 699 for (int idx = 1; idx < pts; ++idx) { |
| 695 double test = fabs(intersections[0][idx] - mid); | 700 double test = fabs(intersections[0][idx] - mid); |
| 696 if (closest > test) { | 701 if (closest > test) { |
| 697 closestIdx = idx; | 702 closestIdx = idx; |
| 698 closest = test; | 703 closest = test; |
| 699 } | 704 } |
| 700 } | 705 } |
| 701 intersections.quickRemoveOne(closestIdx, --pts); | 706 intersections.quickRemoveOne(closestIdx, --pts); |
| 702 } | 707 } |
| 703 double bestT = -1; | 708 double bestT = -1; |
| 704 for (int index = 0; index < pts; ++index) { | 709 for (int index = 0; index < pts; ++index) { |
| 705 double foundT = intersections[0][index]; | 710 double foundT = intersections[0][index]; |
| 706 if (approximately_less_than_zero(foundT) | 711 if (approximately_less_than_zero(foundT) |
| 707 || approximately_greater_than_one(foundT)) { | 712 || approximately_greater_than_one(foundT)) { |
| 708 continue; | 713 continue; |
| 709 } | 714 } |
| 710 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fo
undT).fY; | 715 SkScalar testY = (*CurvePointAtT[fVerb])(fPts, fWeight, foundT).fY; |
| 711 if (approximately_negative(testY - *bestY) | 716 if (approximately_negative(testY - *bestY) |
| 712 || approximately_negative(basePt.fY - testY)) { | 717 || approximately_negative(basePt.fY - testY)) { |
| 713 continue; | 718 continue; |
| 714 } | 719 } |
| 715 if (pts > 1 && fVerb == SkPath::kLine_Verb) { | 720 if (pts > 1 && fVerb == SkPath::kLine_Verb) { |
| 716 *vertical = true; | 721 *vertical = true; |
| 717 return NULL; // if the intersection is edge on, wait for another on
e | 722 return NULL; // if the intersection is edge on, wait for another on
e |
| 718 } | 723 } |
| 719 if (fVerb > SkPath::kLine_Verb) { | 724 if (fVerb > SkPath::kLine_Verb) { |
| 720 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, f
oundT).fX; | 725 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, foundT).fX; |
| 721 if (approximately_zero(dx)) { | 726 if (approximately_zero(dx)) { |
| 722 *vertical = true; | 727 *vertical = true; |
| 723 return NULL; // hit vertical, wait for another one | 728 return NULL; // hit vertical, wait for another one |
| 724 } | 729 } |
| 725 } | 730 } |
| 726 *bestY = testY; | 731 *bestY = testY; |
| 727 bestT = foundT; | 732 bestT = foundT; |
| 728 } | 733 } |
| 729 if (bestT < 0) { | 734 if (bestT < 0) { |
| 730 return NULL; | 735 return NULL; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 760 } | 765 } |
| 761 | 766 |
| 762 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) { | 767 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) { |
| 763 SkDPoint testPt = this->dPtAtT(t); | 768 SkDPoint testPt = this->dPtAtT(t); |
| 764 SkDLine testPerp = {{ testPt, testPt }}; | 769 SkDLine testPerp = {{ testPt, testPt }}; |
| 765 SkDVector slope = this->dSlopeAtT(t); | 770 SkDVector slope = this->dSlopeAtT(t); |
| 766 testPerp[1].fX += slope.fY; | 771 testPerp[1].fX += slope.fY; |
| 767 testPerp[1].fY -= slope.fX; | 772 testPerp[1].fY -= slope.fX; |
| 768 SkIntersections i; | 773 SkIntersections i; |
| 769 SkOpSegment* oppSegment = oppAngle->segment(); | 774 SkOpSegment* oppSegment = oppAngle->segment(); |
| 770 int oppPtCount = SkPathOpsVerbToPoints(oppSegment->verb()); | 775 (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weig
ht(), testPerp, &i); |
| 771 (*CurveIntersectRay[oppPtCount])(oppSegment->pts(), testPerp, &i); | |
| 772 double closestDistSq = SK_ScalarInfinity; | 776 double closestDistSq = SK_ScalarInfinity; |
| 773 for (int index = 0; index < i.used(); ++index) { | 777 for (int index = 0; index < i.used(); ++index) { |
| 774 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
{ | 778 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t()))
{ |
| 775 continue; | 779 continue; |
| 776 } | 780 } |
| 777 double testDistSq = testPt.distanceSquared(i.pt(index)); | 781 double testDistSq = testPt.distanceSquared(i.pt(index)); |
| 778 if (closestDistSq > testDistSq) { | 782 if (closestDistSq > testDistSq) { |
| 779 closestDistSq = testDistSq; | 783 closestDistSq = testDistSq; |
| 780 } | 784 } |
| 781 } | 785 } |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1154 __FUNCTION__, | 1158 __FUNCTION__, |
| 1155 swap, leftSegment->debugInflections(start, end), | 1159 swap, leftSegment->debugInflections(start, end), |
| 1156 leftSegment->monotonicInY(start, end)); | 1160 leftSegment->monotonicInY(start, end)); |
| 1157 #endif | 1161 #endif |
| 1158 if (swap) { | 1162 if (swap) { |
| 1159 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first | 1163 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first |
| 1160 // sorted but merely the first not already processed (i.e., not done) | 1164 // sorted but merely the first not already processed (i.e., not done) |
| 1161 SkTSwap(*startPtr, *endPtr); | 1165 SkTSwap(*startPtr, *endPtr); |
| 1162 } | 1166 } |
| 1163 } | 1167 } |
| 1168 // FIXME: clockwise isn't reliable -- try computing swap from tangent ? |
| 1164 } | 1169 } |
| 1165 return leftSegment; | 1170 return leftSegment; |
| 1166 } | 1171 } |
| 1167 | 1172 |
| 1168 SkOpGlobalState* SkOpSegment::globalState() const { | 1173 SkOpGlobalState* SkOpSegment::globalState() const { |
| 1169 return contour()->globalState(); | 1174 return contour()->globalState(); |
| 1170 } | 1175 } |
| 1171 | 1176 |
| 1172 void SkOpSegment::init(SkPoint pts[], SkOpContour* contour, SkPath::Verb verb) { | 1177 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { |
| 1173 fContour = contour; | 1178 fContour = contour; |
| 1174 fNext = NULL; | 1179 fNext = NULL; |
| 1175 fPts = pts; | 1180 fPts = pts; |
| 1181 fWeight = weight; |
| 1176 fVerb = verb; | 1182 fVerb = verb; |
| 1177 fCount = 0; | 1183 fCount = 0; |
| 1178 fDoneCount = 0; | 1184 fDoneCount = 0; |
| 1179 fVisited = false; | 1185 fVisited = false; |
| 1180 SkOpSpan* zeroSpan = &fHead; | 1186 SkOpSpan* zeroSpan = &fHead; |
| 1181 zeroSpan->init(this, NULL, 0, fPts[0]); | 1187 zeroSpan->init(this, NULL, 0, fPts[0]); |
| 1182 SkOpSpanBase* oneSpan = &fTail; | 1188 SkOpSpanBase* oneSpan = &fTail; |
| 1183 zeroSpan->setNext(oneSpan); | 1189 zeroSpan->setNext(oneSpan); |
| 1184 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); | 1190 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
| 1185 PATH_OPS_DEBUG_CODE(fID = globalState()->nextSegmentID()); | 1191 SkDEBUGCODE(fID = globalState()->nextSegmentID()); |
| 1186 } | 1192 } |
| 1187 | 1193 |
| 1188 void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, | 1194 void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, |
| 1189 SkOpAngle::IncludeType angleIncludeType) { | 1195 SkOpAngle::IncludeType angleIncludeType) { |
| 1190 int local = SkOpSegment::SpanSign(start, end); | 1196 int local = SkOpSegment::SpanSign(start, end); |
| 1191 SkDEBUGCODE(bool success); | 1197 SkDEBUGCODE(bool success); |
| 1192 if (angleIncludeType == SkOpAngle::kBinarySingle) { | 1198 if (angleIncludeType == SkOpAngle::kBinarySingle) { |
| 1193 int oppLocal = SkOpSegment::OppSign(start, end); | 1199 int oppLocal = SkOpSegment::OppSign(start, end); |
| 1194 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal,
NULL); | 1200 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal,
NULL); |
| 1195 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 1201 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1208 sign or not. However, this isn't enough. | 1214 sign or not. However, this isn't enough. |
| 1209 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. | 1215 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. |
| 1210 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed | 1216 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed |
| 1211 from has the same x direction as this span, the winding should change. If the dx
is opposite, then | 1217 from has the same x direction as this span, the winding should change. If the dx
is opposite, then |
| 1212 the same winding is shared by both. | 1218 the same winding is shared by both. |
| 1213 */ | 1219 */ |
| 1214 bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi
t, | 1220 bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi
t, |
| 1215 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) { | 1221 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) { |
| 1216 SkASSERT(this == start->segment()); | 1222 SkASSERT(this == start->segment()); |
| 1217 SkASSERT(hitDx || !winding); | 1223 SkASSERT(hitDx || !winding); |
| 1218 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; | 1224 SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX; |
| 1219 // SkASSERT(dx); | 1225 // SkASSERT(dx); |
| 1220 int windVal = start->starter(end)->windValue(); | 1226 int windVal = start->starter(end)->windValue(); |
| 1221 #if DEBUG_WINDING_AT_T | 1227 #if DEBUG_WINDING_AT_T |
| 1222 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d
ebugID(), winding, | 1228 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d
ebugID(), winding, |
| 1223 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); | 1229 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); |
| 1224 #endif | 1230 #endif |
| 1225 int sideWind = winding + (dx < 0 ? windVal : -windVal); | 1231 int sideWind = winding + (dx < 0 ? windVal : -windVal); |
| 1226 if (abs(winding) < abs(sideWind)) { | 1232 if (abs(winding) < abs(sideWind)) { |
| 1227 winding = sideWind; | 1233 winding = sideWind; |
| 1228 } | 1234 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1242 #endif | 1248 #endif |
| 1243 // if this fails to mark (because the edges are too small) inform caller to
try again | 1249 // if this fails to mark (because the edges are too small) inform caller to
try again |
| 1244 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL); | 1250 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL); |
| 1245 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 1251 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| 1246 success |= markAndChaseWinding(end, start, winding, oppWind, NULL); | 1252 success |= markAndChaseWinding(end, start, winding, oppWind, NULL); |
| 1247 return success; | 1253 return success; |
| 1248 } | 1254 } |
| 1249 | 1255 |
| 1250 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { | 1256 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const { |
| 1251 SkDPoint cPt = this->dPtAtT(t); | 1257 SkDPoint cPt = this->dPtAtT(t); |
| 1252 int pts = SkPathOpsVerbToPoints(this->verb()); | 1258 SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight()
, t); |
| 1253 SkDVector dxdy = (*CurveDSlopeAtT[pts])(this->pts(), t); | |
| 1254 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; | 1259 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; |
| 1255 SkIntersections i; | 1260 SkIntersections i; |
| 1256 int oppPts = SkPathOpsVerbToPoints(opp->verb()); | 1261 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i); |
| 1257 (*CurveIntersectRay[oppPts])(opp->pts(), perp, &i); | |
| 1258 int used = i.used(); | 1262 int used = i.used(); |
| 1259 for (int index = 0; index < used; ++index) { | 1263 for (int index = 0; index < used; ++index) { |
| 1260 if (cPt.roughlyEqual(i.pt(index))) { | 1264 if (cPt.roughlyEqual(i.pt(index))) { |
| 1261 return true; | 1265 return true; |
| 1262 } | 1266 } |
| 1263 } | 1267 } |
| 1264 return false; | 1268 return false; |
| 1265 } | 1269 } |
| 1266 | 1270 |
| 1267 bool SkOpSegment::isXor() const { | 1271 bool SkOpSegment::isXor() const { |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1446 } | 1450 } |
| 1447 return NULL; | 1451 return NULL; |
| 1448 } | 1452 } |
| 1449 | 1453 |
| 1450 bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en
d) const { | 1454 bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en
d) const { |
| 1451 SkASSERT(fVerb != SkPath::kLine_Verb); | 1455 SkASSERT(fVerb != SkPath::kLine_Verb); |
| 1452 if (fVerb == SkPath::kQuad_Verb) { | 1456 if (fVerb == SkPath::kQuad_Verb) { |
| 1453 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t()); | 1457 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t()); |
| 1454 return dst.monotonicInY(); | 1458 return dst.monotonicInY(); |
| 1455 } | 1459 } |
| 1460 if (fVerb == SkPath::kConic_Verb) { |
| 1461 SkDConic dst = SkDConic::SubDivide(fPts, fWeight, start->t(), end->t()); |
| 1462 return dst.monotonicInY(); |
| 1463 } |
| 1456 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1464 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1457 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); | 1465 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); |
| 1458 return dst.monotonicInY(); | 1466 return dst.monotonicInY(); |
| 1459 } | 1467 } |
| 1460 | 1468 |
| 1461 bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, | 1469 bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, |
| 1462 SkOpSpanBase** end) { | 1470 SkOpSpanBase** end) { |
| 1463 while (span->final() || span->upCast()->done()) { | 1471 while (span->final() || span->upCast()->done()) { |
| 1464 if (span->final()) { | 1472 if (span->final()) { |
| 1465 return false; | 1473 return false; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1608 { | 1616 { |
| 1609 // average t, find mid pt | 1617 // average t, find mid pt |
| 1610 double midT = (prior->t() + span->t()) / 2; | 1618 double midT = (prior->t() + span->t()) / 2; |
| 1611 SkPoint midPt = this->ptAtT(midT); | 1619 SkPoint midPt = this->ptAtT(midT); |
| 1612 coincident = true; | 1620 coincident = true; |
| 1613 // if the mid pt is not near either end pt, project perpendicula
r through opp seg | 1621 // if the mid pt is not near either end pt, project perpendicula
r through opp seg |
| 1614 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) | 1622 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt) |
| 1615 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { | 1623 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) { |
| 1616 coincident = false; | 1624 coincident = false; |
| 1617 SkIntersections i; | 1625 SkIntersections i; |
| 1618 int ptCount = SkPathOpsVerbToPoints(this->verb()); | 1626 SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->w
eight(), midT); |
| 1619 SkVector dxdy = (*CurveSlopeAtT[ptCount])(pts(), midT); | |
| 1620 SkDLine ray = {{{midPt.fX, midPt.fY}, | 1627 SkDLine ray = {{{midPt.fX, midPt.fY}, |
| 1621 {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}}; | 1628 {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}}; |
| 1622 int oppPtCount = SkPathOpsVerbToPoints(opp->verb()); | 1629 (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(),
ray, &i); |
| 1623 (*CurveIntersectRay[oppPtCount])(opp->pts(), ray, &i); | |
| 1624 // measure distance and see if it's small enough to denote c
oincidence | 1630 // measure distance and see if it's small enough to denote c
oincidence |
| 1625 for (int index = 0; index < i.used(); ++index) { | 1631 for (int index = 0; index < i.used(); ++index) { |
| 1626 SkDPoint oppPt = i.pt(index); | 1632 SkDPoint oppPt = i.pt(index); |
| 1627 if (oppPt.approximatelyEqual(midPt)) { | 1633 if (oppPt.approximatelyEqual(midPt)) { |
| 1628 SkVector oppDxdy = (*CurveSlopeAtT[oppPtCount])(opp-
>pts(), | 1634 SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp
->pts(), |
| 1629 i[index][0]); | 1635 opp->weight(), i[index][0]); |
| 1630 oppDxdy.normalize(); | 1636 oppDxdy.normalize(); |
| 1631 dxdy.normalize(); | 1637 dxdy.normalize(); |
| 1632 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy)
/ FLT_EPSILON); | 1638 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy)
/ FLT_EPSILON); |
| 1633 coincident |= flatness < 5000; // FIXME: replace wi
th tuned value | 1639 coincident |= flatness < 5000; // FIXME: replace wi
th tuned value |
| 1634 } | 1640 } |
| 1635 } | 1641 } |
| 1636 } | 1642 } |
| 1637 } | 1643 } |
| 1638 if (coincident) { | 1644 if (coincident) { |
| 1639 // mark coincidence | 1645 // mark coincidence |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1822 baseAngle = NULL; | 1828 baseAngle = NULL; |
| 1823 } | 1829 } |
| 1824 #if DEBUG_SORT | 1830 #if DEBUG_SORT |
| 1825 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); | 1831 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); |
| 1826 #endif | 1832 #endif |
| 1827 } while (!span->final() && (span = span->upCast()->next())); | 1833 } while (!span->final() && (span = span->upCast()->next())); |
| 1828 } | 1834 } |
| 1829 | 1835 |
| 1830 // return true if midpoints were computed | 1836 // return true if midpoints were computed |
| 1831 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, | 1837 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 1832 SkPoint edge[4]) const { | 1838 SkOpCurve* edge) const { |
| 1833 SkASSERT(start != end); | 1839 SkASSERT(start != end); |
| 1834 const SkOpPtT& startPtT = *start->ptT(); | 1840 const SkOpPtT& startPtT = *start->ptT(); |
| 1835 const SkOpPtT& endPtT = *end->ptT(); | 1841 const SkOpPtT& endPtT = *end->ptT(); |
| 1836 edge[0] = startPtT.fPt; | 1842 SkDEBUGCODE(edge->fVerb = fVerb); |
| 1843 edge->fPts[0] = startPtT.fPt; |
| 1837 int points = SkPathOpsVerbToPoints(fVerb); | 1844 int points = SkPathOpsVerbToPoints(fVerb); |
| 1838 edge[points] = endPtT.fPt; | 1845 edge->fPts[points] = endPtT.fPt; |
| 1846 edge->fWeight = 1; |
| 1839 if (fVerb == SkPath::kLine_Verb) { | 1847 if (fVerb == SkPath::kLine_Verb) { |
| 1840 return false; | 1848 return false; |
| 1841 } | 1849 } |
| 1842 double startT = startPtT.fT; | 1850 double startT = startPtT.fT; |
| 1843 double endT = endPtT.fT; | 1851 double endT = endPtT.fT; |
| 1844 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { | 1852 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { |
| 1845 // don't compute midpoints if we already have them | 1853 // don't compute midpoints if we already have them |
| 1846 if (fVerb == SkPath::kQuad_Verb) { | 1854 if (fVerb == SkPath::kQuad_Verb) { |
| 1847 edge[1] = fPts[1]; | 1855 edge->fPts[1] = fPts[1]; |
| 1856 return false; |
| 1857 } |
| 1858 if (fVerb == SkPath::kConic_Verb) { |
| 1859 edge->fPts[1] = fPts[1]; |
| 1860 edge->fWeight = fWeight; |
| 1848 return false; | 1861 return false; |
| 1849 } | 1862 } |
| 1850 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1863 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1851 if (start < end) { | 1864 if (start < end) { |
| 1852 edge[1] = fPts[1]; | 1865 edge->fPts[1] = fPts[1]; |
| 1853 edge[2] = fPts[2]; | 1866 edge->fPts[2] = fPts[2]; |
| 1854 return false; | 1867 return false; |
| 1855 } | 1868 } |
| 1856 edge[1] = fPts[2]; | 1869 edge->fPts[1] = fPts[2]; |
| 1857 edge[2] = fPts[1]; | 1870 edge->fPts[2] = fPts[1]; |
| 1858 return false; | 1871 return false; |
| 1859 } | 1872 } |
| 1860 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[p
oints].fY }}; | 1873 const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY}, |
| 1874 {edge->fPts[points].fX, edge->fPts[points].fY }}; |
| 1861 if (fVerb == SkPath::kQuad_Verb) { | 1875 if (fVerb == SkPath::kQuad_Verb) { |
| 1862 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoi
nt(); | 1876 edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).a
sSkPoint(); |
| 1877 } else if (fVerb == SkPath::kConic_Verb) { |
| 1878 edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1], |
| 1879 startT, endT, &edge->fWeight).asSkPoint(); |
| 1863 } else { | 1880 } else { |
| 1864 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1881 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1865 SkDPoint ctrl[2]; | 1882 SkDPoint ctrl[2]; |
| 1866 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); | 1883 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); |
| 1867 edge[1] = ctrl[0].asSkPoint(); | 1884 edge->fPts[1] = ctrl[0].asSkPoint(); |
| 1868 edge[2] = ctrl[1].asSkPoint(); | 1885 edge->fPts[2] = ctrl[1].asSkPoint(); |
| 1869 } | 1886 } |
| 1870 return true; | 1887 return true; |
| 1871 } | 1888 } |
| 1872 | 1889 |
| 1873 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, | 1890 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, |
| 1874 SkDCubic* result) const { | 1891 SkDCurve* edge) const { |
| 1875 SkASSERT(start != end); | 1892 SkASSERT(start != end); |
| 1876 const SkOpPtT& startPtT = *start->ptT(); | 1893 const SkOpPtT& startPtT = *start->ptT(); |
| 1877 const SkOpPtT& endPtT = *end->ptT(); | 1894 const SkOpPtT& endPtT = *end->ptT(); |
| 1878 (*result)[0].set(startPtT.fPt); | 1895 SkDEBUGCODE(edge->fVerb = fVerb); |
| 1896 edge->fCubic[0].set(startPtT.fPt); |
| 1879 int points = SkPathOpsVerbToPoints(fVerb); | 1897 int points = SkPathOpsVerbToPoints(fVerb); |
| 1880 (*result)[points].set(endPtT.fPt); | 1898 edge->fCubic[points].set(endPtT.fPt); |
| 1881 if (fVerb == SkPath::kLine_Verb) { | 1899 if (fVerb == SkPath::kLine_Verb) { |
| 1882 return false; | 1900 return false; |
| 1883 } | 1901 } |
| 1884 double startT = startPtT.fT; | 1902 double startT = startPtT.fT; |
| 1885 double endT = endPtT.fT; | 1903 double endT = endPtT.fT; |
| 1886 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { | 1904 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { |
| 1887 // don't compute midpoints if we already have them | 1905 // don't compute midpoints if we already have them |
| 1888 if (fVerb == SkPath::kQuad_Verb) { | 1906 if (fVerb == SkPath::kQuad_Verb) { |
| 1889 (*result)[1].set(fPts[1]); | 1907 edge->fLine[1].set(fPts[1]); |
| 1908 return false; |
| 1909 } |
| 1910 if (fVerb == SkPath::kConic_Verb) { |
| 1911 edge->fConic[1].set(fPts[1]); |
| 1912 edge->fConic.fWeight = fWeight; |
| 1890 return false; | 1913 return false; |
| 1891 } | 1914 } |
| 1892 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1915 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1893 if (startT == 0) { | 1916 if (startT == 0) { |
| 1894 (*result)[1].set(fPts[1]); | 1917 edge->fCubic[1].set(fPts[1]); |
| 1895 (*result)[2].set(fPts[2]); | 1918 edge->fCubic[2].set(fPts[2]); |
| 1896 return false; | 1919 return false; |
| 1897 } | 1920 } |
| 1898 (*result)[1].set(fPts[2]); | 1921 edge->fCubic[1].set(fPts[2]); |
| 1899 (*result)[2].set(fPts[1]); | 1922 edge->fCubic[2].set(fPts[1]); |
| 1900 return false; | 1923 return false; |
| 1901 } | 1924 } |
| 1902 if (fVerb == SkPath::kQuad_Verb) { | 1925 if (fVerb == SkPath::kQuad_Verb) { |
| 1903 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], star
tT, endT); | 1926 edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2]
, startT, endT); |
| 1927 } else if (fVerb == SkPath::kConic_Verb) { |
| 1928 edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edg
e->fQuad[2], |
| 1929 startT, endT, &edge->fConic.fWeight); |
| 1904 } else { | 1930 } else { |
| 1905 SkASSERT(fVerb == SkPath::kCubic_Verb); | 1931 SkASSERT(fVerb == SkPath::kCubic_Verb); |
| 1906 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*r
esult)[1]); | 1932 SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT
, &edge->fCubic[1]); |
| 1907 } | 1933 } |
| 1908 return true; | 1934 return true; |
| 1909 } | 1935 } |
| 1910 | 1936 |
| 1911 void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase*
end, | 1937 void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase*
end, |
| 1912 SkPathOpsBounds* bounds) const { | 1938 SkPathOpsBounds* bounds) const { |
| 1913 SkPoint edge[4]; | 1939 SkOpCurve edge; |
| 1914 subDivide(start, end, edge); | 1940 subDivide(start, end, &edge); |
| 1915 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); | 1941 (bounds->*SetCurveBounds[fVerb])(edge.fPts, edge.fWeight); |
| 1916 } | 1942 } |
| 1917 | 1943 |
| 1918 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { | 1944 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { |
| 1919 SkOpSpan* span = this->head(); | 1945 SkOpSpan* span = this->head(); |
| 1920 do { | 1946 do { |
| 1921 if (!span->done()) { | 1947 if (!span->done()) { |
| 1922 break; | 1948 break; |
| 1923 } | 1949 } |
| 1924 } while ((span = span->next()->upCastable())); | 1950 } while ((span = span->next()->upCastable())); |
| 1925 SkASSERT(span); | 1951 SkASSERT(span); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1994 return SK_MinS32; | 2020 return SK_MinS32; |
| 1995 } | 2021 } |
| 1996 int winding = crossOpp ? span->oppSum() : span->windSum(); | 2022 int winding = crossOpp ? span->oppSum() : span->windSum(); |
| 1997 SkASSERT(winding != SK_MinS32); | 2023 SkASSERT(winding != SK_MinS32); |
| 1998 int windVal = crossOpp ? span->oppValue() : span->windValue(); | 2024 int windVal = crossOpp ? span->oppValue() : span->windValue(); |
| 1999 #if DEBUG_WINDING_AT_T | 2025 #if DEBUG_WINDING_AT_T |
| 2000 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __
FUNCTION__, | 2026 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __
FUNCTION__, |
| 2001 debugID(), crossOpp, tHit, span->t(), winding, windVal); | 2027 debugID(), crossOpp, tHit, span->t(), winding, windVal); |
| 2002 #endif | 2028 #endif |
| 2003 // see if a + change in T results in a +/- change in X (compute x'(T)) | 2029 // see if a + change in T results in a +/- change in X (compute x'(T)) |
| 2004 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; | 2030 *dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX; |
| 2005 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { | 2031 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { |
| 2006 *dx = fPts[2].fX - fPts[1].fX - *dx; | 2032 *dx = fPts[2].fX - fPts[1].fX - *dx; |
| 2007 } | 2033 } |
| 2008 if (*dx == 0) { | 2034 if (*dx == 0) { |
| 2009 #if DEBUG_WINDING_AT_T | 2035 #if DEBUG_WINDING_AT_T |
| 2010 SkDebugf(" dx=0 winding=SK_MinS32\n"); | 2036 SkDebugf(" dx=0 winding=SK_MinS32\n"); |
| 2011 #endif | 2037 #endif |
| 2012 return SK_MinS32; | 2038 return SK_MinS32; |
| 2013 } | 2039 } |
| 2014 if (windVal < 0) { // reverse sign if opp contour traveled in reverse | 2040 if (windVal < 0) { // reverse sign if opp contour traveled in reverse |
| 2015 *dx = -*dx; | 2041 *dx = -*dx; |
| 2016 } | 2042 } |
| 2017 if (winding * *dx > 0) { // if same signs, result is negative | 2043 if (winding * *dx > 0) { // if same signs, result is negative |
| 2018 winding += *dx > 0 ? -windVal : windVal; | 2044 winding += *dx > 0 ? -windVal : windVal; |
| 2019 } | 2045 } |
| 2020 #if DEBUG_WINDING_AT_T | 2046 #if DEBUG_WINDING_AT_T |
| 2021 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); | 2047 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); |
| 2022 #endif | 2048 #endif |
| 2023 return winding; | 2049 return winding; |
| 2024 } | 2050 } |
| 2025 | 2051 |
| 2026 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 2052 int SkOpSegment::windSum(const SkOpAngle* angle) const { |
| 2027 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); | 2053 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); |
| 2028 return minSpan->windSum(); | 2054 return minSpan->windSum(); |
| 2029 } | 2055 } |
| OLD | NEW |