| Index: src/pathops/SkOpContour.cpp
|
| diff --git a/src/pathops/SkOpContour.cpp b/src/pathops/SkOpContour.cpp
|
| index 28c072a3c1340200c2cd7f1b2514bd20b19e2c05..d17b18905beeba9a9c3cb86bc72a1d3901ed7fe6 100644
|
| --- a/src/pathops/SkOpContour.cpp
|
| +++ b/src/pathops/SkOpContour.cpp
|
| @@ -4,42 +4,35 @@
|
| * Use of this source code is governed by a BSD-style license that can be
|
| * found in the LICENSE file.
|
| */
|
| -#include "SkIntersections.h"
|
| #include "SkOpContour.h"
|
| +#include "SkOpTAllocator.h"
|
| #include "SkPathWriter.h"
|
| +#include "SkReduceOrder.h"
|
| #include "SkTSort.h"
|
|
|
| -bool SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex,
|
| - const SkIntersections& ts, bool swap) {
|
| - SkPoint pt0 = ts.pt(0).asSkPoint();
|
| - SkPoint pt1 = ts.pt(1).asSkPoint();
|
| - if (pt0 == pt1 || ts[0][0] == ts[0][1] || ts[1][0] == ts[1][1]) {
|
| - // FIXME: one could imagine a case where it would be incorrect to ignore this
|
| - // suppose two self-intersecting cubics overlap to be coincident --
|
| - // this needs to check that by some measure the t values are far enough apart
|
| - // or needs to check to see if the self-intersection bit was set on the cubic segment
|
| - return false;
|
| - }
|
| - SkCoincidence& coincidence = fCoincidences.push_back();
|
| - coincidence.fOther = other;
|
| - coincidence.fSegments[0] = index;
|
| - coincidence.fSegments[1] = otherIndex;
|
| - coincidence.fTs[swap][0] = ts[0][0];
|
| - coincidence.fTs[swap][1] = ts[0][1];
|
| - coincidence.fTs[!swap][0] = ts[1][0];
|
| - coincidence.fTs[!swap][1] = ts[1][1];
|
| - coincidence.fPts[swap][0] = pt0;
|
| - coincidence.fPts[swap][1] = pt1;
|
| - bool nearStart = ts.nearlySame(0);
|
| - bool nearEnd = ts.nearlySame(1);
|
| - coincidence.fPts[!swap][0] = nearStart ? ts.pt2(0).asSkPoint() : pt0;
|
| - coincidence.fPts[!swap][1] = nearEnd ? ts.pt2(1).asSkPoint() : pt1;
|
| - coincidence.fNearly[0] = nearStart;
|
| - coincidence.fNearly[1] = nearEnd;
|
| - return true;
|
| -}
|
| -
|
| -SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) {
|
| +void SkOpContour::addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocator) {
|
| + switch (verb) {
|
| + case SkPath::kLine_Verb: {
|
| + SkPoint* ptStorage = SkOpTAllocator<SkPoint>::AllocateArray(allocator, 2);
|
| + memcpy(ptStorage, pts, sizeof(SkPoint) * 2);
|
| + appendSegment(allocator).addLine(ptStorage, this);
|
| + } break;
|
| + case SkPath::kQuad_Verb: {
|
| + SkPoint* ptStorage = SkOpTAllocator<SkPoint>::AllocateArray(allocator, 3);
|
| + memcpy(ptStorage, pts, sizeof(SkPoint) * 3);
|
| + appendSegment(allocator).addQuad(ptStorage, this);
|
| + } break;
|
| + case SkPath::kCubic_Verb: {
|
| + SkPoint* ptStorage = SkOpTAllocator<SkPoint>::AllocateArray(allocator, 4);
|
| + memcpy(ptStorage, pts, sizeof(SkPoint) * 4);
|
| + appendSegment(allocator).addCubic(ptStorage, this);
|
| + } break;
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| +}
|
| +
|
| +SkOpSegment* SkOpContour::nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end) {
|
| int segmentCount = fSortedSegments.count();
|
| SkASSERT(segmentCount > 0);
|
| for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
|
| @@ -47,627 +40,27 @@ SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) {
|
| if (testSegment->done()) {
|
| continue;
|
| }
|
| - *start = *end = 0;
|
| - while (testSegment->nextCandidate(start, end)) {
|
| - if (!testSegment->isVertical(*start, *end)) {
|
| + SkOpSpanBase* span = testSegment->head();
|
| + SkOpSpanBase* testS, * testE;
|
| + while (SkOpSegment::NextCandidate(span, &testS, &testE)) {
|
| + if (!testSegment->isVertical(testS, testE)) {
|
| + *start = testS;
|
| + *end = testE;
|
| return testSegment;
|
| }
|
| + span = span->upCast()->next();
|
| }
|
| }
|
| return NULL;
|
| }
|
|
|
| -// if one is very large the smaller may have collapsed to nothing
|
| -static void bump_out_close_span(double* startTPtr, double* endTPtr) {
|
| - double startT = *startTPtr;
|
| - double endT = *endTPtr;
|
| - if (approximately_negative(endT - startT)) {
|
| - if (endT <= 1 - FLT_EPSILON) {
|
| - *endTPtr += FLT_EPSILON;
|
| - SkASSERT(*endTPtr <= 1);
|
| - } else {
|
| - *startTPtr -= FLT_EPSILON;
|
| - SkASSERT(*startTPtr >= 0);
|
| - }
|
| - }
|
| -}
|
| -
|
| -// first pass, add missing T values
|
| -// second pass, determine winding values of overlaps
|
| -void SkOpContour::addCoincidentPoints() {
|
| - int count = fCoincidences.count();
|
| - for (int index = 0; index < count; ++index) {
|
| - SkCoincidence& coincidence = fCoincidences[index];
|
| - int thisIndex = coincidence.fSegments[0];
|
| - SkOpSegment& thisOne = fSegments[thisIndex];
|
| - SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - SkOpSegment& other = otherContour->fSegments[otherIndex];
|
| - if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
|
| - // OPTIMIZATION: remove from array
|
| - continue;
|
| - }
|
| - #if DEBUG_CONCIDENT
|
| - thisOne.debugShowTs("-");
|
| - other.debugShowTs("o");
|
| - #endif
|
| - double startT = coincidence.fTs[0][0];
|
| - double endT = coincidence.fTs[0][1];
|
| - bool startSwapped, oStartSwapped, cancelers;
|
| - if ((cancelers = startSwapped = startT > endT)) {
|
| - SkTSwap(startT, endT);
|
| - }
|
| - bump_out_close_span(&startT, &endT);
|
| - SkASSERT(!approximately_negative(endT - startT));
|
| - double oStartT = coincidence.fTs[1][0];
|
| - double oEndT = coincidence.fTs[1][1];
|
| - if ((oStartSwapped = oStartT > oEndT)) {
|
| - SkTSwap(oStartT, oEndT);
|
| - cancelers ^= true;
|
| - }
|
| - bump_out_close_span(&oStartT, &oEndT);
|
| - SkASSERT(!approximately_negative(oEndT - oStartT));
|
| - const SkPoint& startPt = coincidence.fPts[0][startSwapped];
|
| - if (cancelers) {
|
| - // make sure startT and endT have t entries
|
| - if (startT > 0 || oEndT < 1
|
| - || thisOne.isMissing(startT, startPt) || other.isMissing(oEndT, startPt)) {
|
| - thisOne.addTPair(startT, &other, oEndT, true, startPt,
|
| - coincidence.fPts[1][startSwapped]);
|
| - }
|
| - const SkPoint& oStartPt = coincidence.fPts[1][oStartSwapped];
|
| - if (oStartT > 0 || endT < 1
|
| - || thisOne.isMissing(endT, oStartPt) || other.isMissing(oStartT, oStartPt)) {
|
| - other.addTPair(oStartT, &thisOne, endT, true, oStartPt,
|
| - coincidence.fPts[0][oStartSwapped]);
|
| - }
|
| - } else {
|
| - if (startT > 0 || oStartT > 0
|
| - || thisOne.isMissing(startT, startPt) || other.isMissing(oStartT, startPt)) {
|
| - thisOne.addTPair(startT, &other, oStartT, true, startPt,
|
| - coincidence.fPts[1][startSwapped]);
|
| - }
|
| - const SkPoint& oEndPt = coincidence.fPts[1][!oStartSwapped];
|
| - if (endT < 1 || oEndT < 1
|
| - || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT, oEndPt)) {
|
| - other.addTPair(oEndT, &thisOne, endT, true, oEndPt,
|
| - coincidence.fPts[0][!oStartSwapped]);
|
| - }
|
| - }
|
| - #if DEBUG_CONCIDENT
|
| - thisOne.debugShowTs("+");
|
| - other.debugShowTs("o");
|
| - #endif
|
| - }
|
| - // if there are multiple pairs of coincidence that share an edge, see if the opposite
|
| - // are also coincident
|
| - for (int index = 0; index < count - 1; ++index) {
|
| - const SkCoincidence& coincidence = fCoincidences[index];
|
| - int thisIndex = coincidence.fSegments[0];
|
| - SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - for (int idx2 = 1; idx2 < count; ++idx2) {
|
| - const SkCoincidence& innerCoin = fCoincidences[idx2];
|
| - int innerThisIndex = innerCoin.fSegments[0];
|
| - if (thisIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 1, innerCoin, 1, false);
|
| - }
|
| - if (this == otherContour && otherIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 0, innerCoin, 1, false);
|
| - }
|
| - SkOpContour* innerOtherContour = innerCoin.fOther;
|
| - innerThisIndex = innerCoin.fSegments[1];
|
| - if (this == innerOtherContour && thisIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 1, innerCoin, 0, false);
|
| - }
|
| - if (otherContour == innerOtherContour && otherIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 0, innerCoin, 0, false);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherIndex,
|
| - const SkIntersections& ts, int ptIndex, bool swap) {
|
| - SkPoint pt0 = ts.pt(ptIndex).asSkPoint();
|
| - SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint();
|
| - if (SkDPoint::ApproximatelyEqual(pt0, pt1)) {
|
| - // FIXME: one could imagine a case where it would be incorrect to ignore this
|
| - // suppose two self-intersecting cubics overlap to form a partial coincidence --
|
| - // although it isn't clear why the regular coincidence could wouldn't pick this up
|
| - // this is exceptional enough to ignore for now
|
| - return false;
|
| - }
|
| - SkCoincidence& coincidence = fPartialCoincidences.push_back();
|
| - coincidence.fOther = other;
|
| - coincidence.fSegments[0] = index;
|
| - coincidence.fSegments[1] = otherIndex;
|
| - coincidence.fTs[swap][0] = ts[0][ptIndex];
|
| - coincidence.fTs[swap][1] = ts[0][ptIndex + 1];
|
| - coincidence.fTs[!swap][0] = ts[1][ptIndex];
|
| - coincidence.fTs[!swap][1] = ts[1][ptIndex + 1];
|
| - coincidence.fPts[0][0] = coincidence.fPts[1][0] = pt0;
|
| - coincidence.fPts[0][1] = coincidence.fPts[1][1] = pt1;
|
| - coincidence.fNearly[0] = 0;
|
| - coincidence.fNearly[1] = 0;
|
| - return true;
|
| -}
|
| -
|
| -void SkOpContour::align(const SkOpSegment::AlignedSpan& aligned, bool swap,
|
| - SkCoincidence* coincidence) {
|
| - for (int idx2 = 0; idx2 < 2; ++idx2) {
|
| - if (coincidence->fPts[0][idx2] == aligned.fOldPt
|
| - && coincidence->fTs[swap][idx2] == aligned.fOldT) {
|
| - SkASSERT(SkDPoint::RoughlyEqual(coincidence->fPts[0][idx2], aligned.fPt));
|
| - coincidence->fPts[0][idx2] = aligned.fPt;
|
| - SkASSERT(way_roughly_equal(coincidence->fTs[swap][idx2], aligned.fT));
|
| - coincidence->fTs[swap][idx2] = aligned.fT;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::alignCoincidence(const SkOpSegment::AlignedSpan& aligned,
|
| - SkTArray<SkCoincidence, true>* coincidences) {
|
| - int count = coincidences->count();
|
| - for (int index = 0; index < count; ++index) {
|
| - SkCoincidence& coincidence = (*coincidences)[index];
|
| - int thisIndex = coincidence.fSegments[0];
|
| - const SkOpSegment* thisOne = &fSegments[thisIndex];
|
| - const SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - const SkOpSegment* other = &otherContour->fSegments[otherIndex];
|
| - if (thisOne == aligned.fOther1 && other == aligned.fOther2) {
|
| - align(aligned, false, &coincidence);
|
| - } else if (thisOne == aligned.fOther2 && other == aligned.fOther1) {
|
| - align(aligned, true, &coincidence);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::alignTPt(int segmentIndex, const SkOpContour* other, int otherIndex,
|
| - bool swap, int tIndex, SkIntersections* ts, SkPoint* point) const {
|
| - int zeroPt;
|
| - if ((zeroPt = alignT(swap, tIndex, ts)) >= 0) {
|
| - alignPt(segmentIndex, point, zeroPt);
|
| - }
|
| - if ((zeroPt = other->alignT(!swap, tIndex, ts)) >= 0) {
|
| - other->alignPt(otherIndex, point, zeroPt);
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::alignPt(int index, SkPoint* point, int zeroPt) const {
|
| - const SkOpSegment& segment = fSegments[index];
|
| - if (0 == zeroPt) {
|
| - *point = segment.pts()[0];
|
| - } else {
|
| - *point = segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
|
| - }
|
| -}
|
| -
|
| -int SkOpContour::alignT(bool swap, int tIndex, SkIntersections* ts) const {
|
| - double tVal = (*ts)[swap][tIndex];
|
| - if (tVal != 0 && precisely_zero(tVal)) {
|
| - ts->set(swap, tIndex, 0);
|
| - return 0;
|
| - }
|
| - if (tVal != 1 && precisely_equal(tVal, 1)) {
|
| - ts->set(swap, tIndex, 1);
|
| - return 1;
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -bool SkOpContour::calcAngles() {
|
| - int segmentCount = fSegments.count();
|
| - for (int test = 0; test < segmentCount; ++test) {
|
| - if (!fSegments[test].calcAngles()) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool SkOpContour::calcCoincidentWinding() {
|
| - int count = fCoincidences.count();
|
| -#if DEBUG_CONCIDENT
|
| - if (count > 0) {
|
| - SkDebugf("%s count=%d\n", __FUNCTION__, count);
|
| - }
|
| -#endif
|
| - for (int index = 0; index < count; ++index) {
|
| - SkCoincidence& coincidence = fCoincidences[index];
|
| - if (!calcCommonCoincidentWinding(coincidence)) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void SkOpContour::calcPartialCoincidentWinding() {
|
| - int count = fPartialCoincidences.count();
|
| -#if DEBUG_CONCIDENT
|
| - if (count > 0) {
|
| - SkDebugf("%s count=%d\n", __FUNCTION__, count);
|
| - }
|
| -#endif
|
| - for (int index = 0; index < count; ++index) {
|
| - SkCoincidence& coincidence = fPartialCoincidences[index];
|
| - calcCommonCoincidentWinding(coincidence);
|
| - }
|
| - // if there are multiple pairs of partial coincidence that share an edge, see if the opposite
|
| - // are also coincident
|
| - for (int index = 0; index < count - 1; ++index) {
|
| - const SkCoincidence& coincidence = fPartialCoincidences[index];
|
| - int thisIndex = coincidence.fSegments[0];
|
| - SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - for (int idx2 = 1; idx2 < count; ++idx2) {
|
| - const SkCoincidence& innerCoin = fPartialCoincidences[idx2];
|
| - int innerThisIndex = innerCoin.fSegments[0];
|
| - if (thisIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 1, innerCoin, 1, true);
|
| - }
|
| - if (this == otherContour && otherIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 0, innerCoin, 1, true);
|
| - }
|
| - SkOpContour* innerOtherContour = innerCoin.fOther;
|
| - innerThisIndex = innerCoin.fSegments[1];
|
| - if (this == innerOtherContour && thisIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 1, innerCoin, 0, true);
|
| - }
|
| - if (otherContour == innerOtherContour && otherIndex == innerThisIndex) {
|
| - checkCoincidentPair(coincidence, 0, innerCoin, 0, true);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx,
|
| - const SkCoincidence& twoCoin, int twoIdx, bool partial) {
|
| - SkASSERT((oneIdx ? this : oneCoin.fOther) == (twoIdx ? this : twoCoin.fOther));
|
| - SkASSERT(oneCoin.fSegments[!oneIdx] == twoCoin.fSegments[!twoIdx]);
|
| - // look for common overlap
|
| - double min = SK_ScalarMax;
|
| - double max = SK_ScalarMin;
|
| - double min1 = oneCoin.fTs[!oneIdx][0];
|
| - double max1 = oneCoin.fTs[!oneIdx][1];
|
| - double min2 = twoCoin.fTs[!twoIdx][0];
|
| - double max2 = twoCoin.fTs[!twoIdx][1];
|
| - bool cancelers = (min1 < max1) != (min2 < max2);
|
| - if (min1 > max1) {
|
| - SkTSwap(min1, max1);
|
| - }
|
| - if (min2 > max2) {
|
| - SkTSwap(min2, max2);
|
| - }
|
| - if (between(min1, min2, max1)) {
|
| - min = min2;
|
| - }
|
| - if (between(min1, max2, max1)) {
|
| - max = max2;
|
| - }
|
| - if (between(min2, min1, max2)) {
|
| - min = SkTMin(min, min1);
|
| - }
|
| - if (between(min2, max1, max2)) {
|
| - max = SkTMax(max, max1);
|
| - }
|
| - if (min >= max) {
|
| - return; // no overlap
|
| - }
|
| - // look to see if opposite are different segments
|
| - int seg1Index = oneCoin.fSegments[oneIdx];
|
| - int seg2Index = twoCoin.fSegments[twoIdx];
|
| - if (seg1Index == seg2Index) {
|
| - return;
|
| - }
|
| - SkOpContour* contour1 = oneIdx ? oneCoin.fOther : this;
|
| - SkOpContour* contour2 = twoIdx ? twoCoin.fOther : this;
|
| - SkOpSegment* segment1 = &contour1->fSegments[seg1Index];
|
| - SkOpSegment* segment2 = &contour2->fSegments[seg2Index];
|
| - // find opposite t value ranges corresponding to reference min/max range
|
| - const SkOpContour* refContour = oneIdx ? this : oneCoin.fOther;
|
| - const int refSegIndex = oneCoin.fSegments[!oneIdx];
|
| - const SkOpSegment* refSegment = &refContour->fSegments[refSegIndex];
|
| - int seg1Start = segment1->findOtherT(min, refSegment);
|
| - int seg1End = segment1->findOtherT(max, refSegment);
|
| - int seg2Start = segment2->findOtherT(min, refSegment);
|
| - int seg2End = segment2->findOtherT(max, refSegment);
|
| - // if the opposite pairs already contain min/max, we're done
|
| - if (seg1Start >= 0 && seg1End >= 0 && seg2Start >= 0 && seg2End >= 0) {
|
| - return;
|
| - }
|
| - double loEnd = SkTMin(min1, min2);
|
| - double hiEnd = SkTMax(max1, max2);
|
| - // insert the missing coincident point(s)
|
| - double missingT1 = -1;
|
| - double otherT1 = -1;
|
| - if (seg1Start < 0) {
|
| - if (seg2Start < 0) {
|
| - return;
|
| - }
|
| - missingT1 = segment1->calcMissingTStart(refSegment, loEnd, min, max, hiEnd,
|
| - segment2, seg1End);
|
| - if (missingT1 < 0) {
|
| - return;
|
| - }
|
| - const SkOpSpan* missingSpan = &segment2->span(seg2Start);
|
| - otherT1 = missingSpan->fT;
|
| - } else if (seg2Start < 0) {
|
| - SkASSERT(seg1Start >= 0);
|
| - missingT1 = segment2->calcMissingTStart(refSegment, loEnd, min, max, hiEnd,
|
| - segment1, seg2End);
|
| - if (missingT1 < 0) {
|
| - return;
|
| - }
|
| - const SkOpSpan* missingSpan = &segment1->span(seg1Start);
|
| - otherT1 = missingSpan->fT;
|
| - }
|
| - SkPoint missingPt1;
|
| - SkOpSegment* addTo1 = NULL;
|
| - SkOpSegment* addOther1 = seg1Start < 0 ? segment2 : segment1;
|
| - int minTIndex = refSegment->findExactT(min, addOther1);
|
| - SkASSERT(minTIndex >= 0);
|
| - if (missingT1 >= 0) {
|
| - missingPt1 = refSegment->span(minTIndex).fPt;
|
| - addTo1 = seg1Start < 0 ? segment1 : segment2;
|
| - }
|
| - double missingT2 = -1;
|
| - double otherT2 = -1;
|
| - if (seg1End < 0) {
|
| - if (seg2End < 0) {
|
| - return;
|
| - }
|
| - missingT2 = segment1->calcMissingTEnd(refSegment, loEnd, min, max, hiEnd,
|
| - segment2, seg1Start);
|
| - if (missingT2 < 0) {
|
| - return;
|
| - }
|
| - const SkOpSpan* missingSpan = &segment2->span(seg2End);
|
| - otherT2 = missingSpan->fT;
|
| - } else if (seg2End < 0) {
|
| - SkASSERT(seg1End >= 0);
|
| - missingT2 = segment2->calcMissingTEnd(refSegment, loEnd, min, max, hiEnd,
|
| - segment1, seg2Start);
|
| - if (missingT2 < 0) {
|
| - return;
|
| - }
|
| - const SkOpSpan* missingSpan = &segment1->span(seg1End);
|
| - otherT2 = missingSpan->fT;
|
| - }
|
| - SkPoint missingPt2;
|
| - SkOpSegment* addTo2 = NULL;
|
| - SkOpSegment* addOther2 = seg1End < 0 ? segment2 : segment1;
|
| - int maxTIndex = refSegment->findExactT(max, addOther2);
|
| - SkASSERT(maxTIndex >= 0);
|
| - if (missingT2 >= 0) {
|
| - missingPt2 = refSegment->span(maxTIndex).fPt;
|
| - addTo2 = seg1End < 0 ? segment1 : segment2;
|
| - }
|
| - if (missingT1 >= 0) {
|
| - addTo1->pinT(missingPt1, &missingT1);
|
| - addTo1->addTPair(missingT1, addOther1, otherT1, false, missingPt1);
|
| - } else {
|
| - SkASSERT(minTIndex >= 0);
|
| - missingPt1 = refSegment->span(minTIndex).fPt;
|
| - }
|
| - if (missingT2 >= 0) {
|
| - addTo2->pinT(missingPt2, &missingT2);
|
| - addTo2->addTPair(missingT2, addOther2, otherT2, false, missingPt2);
|
| - } else {
|
| - SkASSERT(minTIndex >= 0);
|
| - missingPt2 = refSegment->span(maxTIndex).fPt;
|
| - }
|
| - if (!partial) {
|
| - return;
|
| - }
|
| - if (cancelers) {
|
| - if (missingT1 >= 0) {
|
| - if (addTo1->reversePoints(missingPt1, missingPt2)) {
|
| - SkTSwap(missingPt1, missingPt2);
|
| - }
|
| - addTo1->addTCancel(missingPt1, missingPt2, addOther1);
|
| - } else {
|
| - if (addTo2->reversePoints(missingPt1, missingPt2)) {
|
| - SkTSwap(missingPt1, missingPt2);
|
| - }
|
| - addTo2->addTCancel(missingPt1, missingPt2, addOther2);
|
| - }
|
| - } else if (missingT1 >= 0) {
|
| - SkAssertResult(addTo1->addTCoincident(missingPt1, missingPt2,
|
| - addTo1 == addTo2 ? missingT2 : otherT2, addOther1));
|
| - } else {
|
| - SkAssertResult(addTo2->addTCoincident(missingPt2, missingPt1,
|
| - addTo2 == addTo1 ? missingT1 : otherT1, addOther2));
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coincidences, bool partial) {
|
| - int count = coincidences.count();
|
| -#if DEBUG_CONCIDENT
|
| - if (count > 0) {
|
| - SkDebugf("%s count=%d\n", __FUNCTION__, count);
|
| - }
|
| -#endif
|
| - // look for a lineup where the partial implies another adjoining coincidence
|
| - for (int index = 0; index < count; ++index) {
|
| - const SkCoincidence& coincidence = coincidences[index];
|
| - int thisIndex = coincidence.fSegments[0];
|
| - SkOpSegment& thisOne = fSegments[thisIndex];
|
| - if (thisOne.done()) {
|
| - continue;
|
| - }
|
| - SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - SkOpSegment& other = otherContour->fSegments[otherIndex];
|
| - if (other.done()) {
|
| - continue;
|
| - }
|
| - double startT = coincidence.fTs[0][0];
|
| - double endT = coincidence.fTs[0][1];
|
| - if (startT == endT) { // this can happen in very large compares
|
| - continue;
|
| - }
|
| - double oStartT = coincidence.fTs[1][0];
|
| - double oEndT = coincidence.fTs[1][1];
|
| - if (oStartT == oEndT) {
|
| - continue;
|
| - }
|
| - bool swapStart = startT > endT;
|
| - bool swapOther = oStartT > oEndT;
|
| - const SkPoint* startPt = &coincidence.fPts[0][0];
|
| - const SkPoint* endPt = &coincidence.fPts[0][1];
|
| - if (swapStart) {
|
| - SkTSwap(startT, endT);
|
| - SkTSwap(oStartT, oEndT);
|
| - SkTSwap(startPt, endPt);
|
| - }
|
| - bool cancel = swapOther != swapStart;
|
| - int step = swapStart ? -1 : 1;
|
| - int oStep = swapOther ? -1 : 1;
|
| - double oMatchStart = cancel ? oEndT : oStartT;
|
| - if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatchStart == 0)) {
|
| - bool added = false;
|
| - if (oMatchStart != 0) {
|
| - const SkPoint& oMatchStartPt = cancel ? *endPt : *startPt;
|
| - added = thisOne.joinCoincidence(&other, oMatchStart, oMatchStartPt, oStep, cancel);
|
| - }
|
| - if (!cancel && startT != 0 && !added) {
|
| - (void) other.joinCoincidence(&thisOne, startT, *startPt, step, cancel);
|
| - }
|
| - }
|
| - double oMatchEnd = cancel ? oStartT : oEndT;
|
| - if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd == 1)) {
|
| - bool added = false;
|
| - if (cancel && endT != 1 && !added) {
|
| - (void) other.joinCoincidence(&thisOne, endT, *endPt, -step, cancel);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence) {
|
| - if (coincidence.fNearly[0] && coincidence.fNearly[1]) {
|
| - return true;
|
| - }
|
| - int thisIndex = coincidence.fSegments[0];
|
| - SkOpSegment& thisOne = fSegments[thisIndex];
|
| - if (thisOne.done()) {
|
| - return true;
|
| - }
|
| - SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - SkOpSegment& other = otherContour->fSegments[otherIndex];
|
| - if (other.done()) {
|
| - return true;
|
| - }
|
| - double startT = coincidence.fTs[0][0];
|
| - double endT = coincidence.fTs[0][1];
|
| - const SkPoint* startPt = &coincidence.fPts[0][0];
|
| - const SkPoint* endPt = &coincidence.fPts[0][1];
|
| - bool cancelers;
|
| - if ((cancelers = startT > endT)) {
|
| - SkTSwap<double>(startT, endT);
|
| - SkTSwap<const SkPoint*>(startPt, endPt);
|
| - }
|
| - bump_out_close_span(&startT, &endT);
|
| - SkASSERT(!approximately_negative(endT - startT));
|
| - double oStartT = coincidence.fTs[1][0];
|
| - double oEndT = coincidence.fTs[1][1];
|
| - if (oStartT > oEndT) {
|
| - SkTSwap<double>(oStartT, oEndT);
|
| - cancelers ^= true;
|
| - }
|
| - bump_out_close_span(&oStartT, &oEndT);
|
| - SkASSERT(!approximately_negative(oEndT - oStartT));
|
| - bool success = true;
|
| - if (cancelers) {
|
| - thisOne.addTCancel(*startPt, *endPt, &other);
|
| - } else {
|
| - success = thisOne.addTCoincident(*startPt, *endPt, endT, &other);
|
| - }
|
| -#if DEBUG_CONCIDENT
|
| - thisOne.debugShowTs("p");
|
| - other.debugShowTs("o");
|
| -#endif
|
| - return success;
|
| -}
|
| -
|
| -void SkOpContour::resolveNearCoincidence() {
|
| - int count = fCoincidences.count();
|
| - for (int index = 0; index < count; ++index) {
|
| - SkCoincidence& coincidence = fCoincidences[index];
|
| - if (!coincidence.fNearly[0] || !coincidence.fNearly[1]) {
|
| - continue;
|
| - }
|
| - int thisIndex = coincidence.fSegments[0];
|
| - SkOpSegment& thisOne = fSegments[thisIndex];
|
| - SkOpContour* otherContour = coincidence.fOther;
|
| - int otherIndex = coincidence.fSegments[1];
|
| - SkOpSegment& other = otherContour->fSegments[otherIndex];
|
| - if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
|
| - // OPTIMIZATION: remove from coincidence array
|
| - continue;
|
| - }
|
| - #if DEBUG_CONCIDENT
|
| - thisOne.debugShowTs("-");
|
| - other.debugShowTs("o");
|
| - #endif
|
| - double startT = coincidence.fTs[0][0];
|
| - double endT = coincidence.fTs[0][1];
|
| - bool cancelers;
|
| - if ((cancelers = startT > endT)) {
|
| - SkTSwap<double>(startT, endT);
|
| - }
|
| - if (startT == endT) { // if span is very large, the smaller may have collapsed to nothing
|
| - if (endT <= 1 - FLT_EPSILON) {
|
| - endT += FLT_EPSILON;
|
| - SkASSERT(endT <= 1);
|
| - } else {
|
| - startT -= FLT_EPSILON;
|
| - SkASSERT(startT >= 0);
|
| - }
|
| - }
|
| - SkASSERT(!approximately_negative(endT - startT));
|
| - double oStartT = coincidence.fTs[1][0];
|
| - double oEndT = coincidence.fTs[1][1];
|
| - if (oStartT > oEndT) {
|
| - SkTSwap<double>(oStartT, oEndT);
|
| - cancelers ^= true;
|
| - }
|
| - SkASSERT(!approximately_negative(oEndT - oStartT));
|
| - if (cancelers) {
|
| - thisOne.blindCancel(coincidence, &other);
|
| - } else {
|
| - thisOne.blindCoincident(coincidence, &other);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::sortAngles() {
|
| - int segmentCount = fSegments.count();
|
| - for (int test = 0; test < segmentCount; ++test) {
|
| - fSegments[test].sortAngles();
|
| - }
|
| -}
|
| -
|
| -void SkOpContour::sortSegments() {
|
| - int segmentCount = fSegments.count();
|
| - fSortedSegments.push_back_n(segmentCount);
|
| - for (int test = 0; test < segmentCount; ++test) {
|
| - fSortedSegments[test] = &fSegments[test];
|
| - }
|
| - SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
|
| - fFirstSorted = 0;
|
| -}
|
| -
|
| void SkOpContour::toPath(SkPathWriter* path) const {
|
| - int segmentCount = fSegments.count();
|
| - const SkPoint& pt = fSegments.front().pts()[0];
|
| + const SkPoint& pt = fHead.pts()[0];
|
| path->deferredMove(pt);
|
| - for (int test = 0; test < segmentCount; ++test) {
|
| - fSegments[test].addCurveTo(0, 1, path, true);
|
| - }
|
| + const SkOpSegment* segment = &fHead;
|
| + do {
|
| + segment->addCurveTo(segment->head(), segment->tail(), path, true);
|
| + } while ((segment = segment->next()));
|
| path->close();
|
| }
|
|
|
| @@ -706,57 +99,14 @@ void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY,
|
| }
|
| }
|
|
|
| -SkOpSegment* SkOpContour::undoneSegment(int* start, int* end) {
|
| - int segmentCount = fSegments.count();
|
| - for (int test = 0; test < segmentCount; ++test) {
|
| - SkOpSegment* testSegment = &fSegments[test];
|
| - if (testSegment->done()) {
|
| +SkOpSegment* SkOpContour::undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr) {
|
| + SkOpSegment* segment = &fHead;
|
| + do {
|
| + if (segment->done()) {
|
| continue;
|
| }
|
| - testSegment->undoneSpan(start, end);
|
| - return testSegment;
|
| - }
|
| + segment->undoneSpan(startPtr, endPtr);
|
| + return segment;
|
| + } while ((segment = segment->next()));
|
| return NULL;
|
| }
|
| -
|
| -#if DEBUG_SHOW_WINDING
|
| -int SkOpContour::debugShowWindingValues(int totalSegments, int ofInterest) {
|
| - int count = fSegments.count();
|
| - int sum = 0;
|
| - for (int index = 0; index < count; ++index) {
|
| - sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
|
| - }
|
| -// SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
|
| - return sum;
|
| -}
|
| -
|
| -void SkOpContour::debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList) {
|
| -// int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
|
| -// int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
|
| - int ofInterest = 1 << 5 | 1 << 8;
|
| - int total = 0;
|
| - int index;
|
| - for (index = 0; index < contourList.count(); ++index) {
|
| - total += contourList[index]->segments().count();
|
| - }
|
| - int sum = 0;
|
| - for (index = 0; index < contourList.count(); ++index) {
|
| - sum += contourList[index]->debugShowWindingValues(total, ofInterest);
|
| - }
|
| -// SkDebugf("%s total=%d\n", __FUNCTION__, sum);
|
| -}
|
| -#endif
|
| -
|
| -void SkOpContour::setBounds() {
|
| - int count = fSegments.count();
|
| - if (count == 0) {
|
| - SkDebugf("%s empty contour\n", __FUNCTION__);
|
| - SkASSERT(0);
|
| - // FIXME: delete empty contour?
|
| - return;
|
| - }
|
| - fBounds = fSegments.front().bounds();
|
| - for (int index = 1; index < count; ++index) {
|
| - fBounds.add(fSegments[index].bounds());
|
| - }
|
| -}
|
|
|