| Index: src/pathops/SkPathOpsCommon.cpp
|
| diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp
|
| index 0e9e1bee8e3065ba3c0c3440f121996e245523f8..9a8a2cf4e31dcd269d624b8a5d7664bcf87d5f8a 100644
|
| --- a/src/pathops/SkPathOpsCommon.cpp
|
| +++ b/src/pathops/SkPathOpsCommon.cpp
|
| @@ -10,6 +10,29 @@
|
| #include "SkPathWriter.h"
|
| #include "SkTSort.h"
|
|
|
| +static void alignMultiples(SkTArray<SkOpContour*, true>* contourList,
|
| + SkTDArray<SkOpSegment::AlignedSpan>* aligned) {
|
| + int contourCount = (*contourList).count();
|
| + for (int cTest = 0; cTest < contourCount; ++cTest) {
|
| + SkOpContour* contour = (*contourList)[cTest];
|
| + if (contour->hasMultiples()) {
|
| + contour->alignMultiples(aligned);
|
| + }
|
| + }
|
| +}
|
| +
|
| +static void alignCoincidence(SkTArray<SkOpContour*, true>* contourList,
|
| + const SkTDArray<SkOpSegment::AlignedSpan>& aligned) {
|
| + int contourCount = (*contourList).count();
|
| + for (int cTest = 0; cTest < contourCount; ++cTest) {
|
| + SkOpContour* contour = (*contourList)[cTest];
|
| + int count = aligned.count();
|
| + for (int index = 0; index < count; ++index) {
|
| + contour->alignCoincidence(aligned[index]);
|
| + }
|
| + }
|
| +}
|
| +
|
| static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr,
|
| int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx,
|
| bool* tryAgain, double* midPtr, bool opp) {
|
| @@ -185,7 +208,7 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex)
|
| if (SkOpSegment::UseInnerWinding(maxWinding, winding)) {
|
| maxWinding = winding;
|
| }
|
| - segment->markAndChaseWinding(angle, maxWinding, 0);
|
| + (void) segment->markAndChaseWinding(angle, maxWinding, 0);
|
| break;
|
| }
|
| }
|
| @@ -204,9 +227,8 @@ void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) {
|
| }
|
| #endif
|
|
|
| -static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| - int* index, int* endIndex, SkPoint* topLeft, bool* unsortable,
|
| - bool* done, bool firstPass) {
|
| +static SkOpSegment* findTopSegment(const SkTArray<SkOpContour*, true>& contourList, int* index,
|
| + int* endIndex, SkPoint* topLeft, bool* unsortable, bool* done, bool firstPass) {
|
| SkOpSegment* result;
|
| const SkOpSegment* lastTopStart = NULL;
|
| int lastIndex = -1, lastEndIndex = -1;
|
| @@ -249,28 +271,27 @@ static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourL
|
| lastEndIndex = *endIndex;
|
| }
|
| } while (!result);
|
| -#if 0
|
| - if (result) {
|
| - *unsortable = false;
|
| - }
|
| -#endif
|
| return result;
|
| }
|
|
|
| static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList,
|
| - SkOpSegment** current, int* index, int* endIndex, double* tHit,
|
| - SkScalar* hitDx, bool* tryAgain, bool opp) {
|
| + SkOpSegment** currentPtr, int* indexPtr, int* endIndexPtr, double* tHit,
|
| + SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) {
|
| double test = 0.9;
|
| int contourWinding;
|
| do {
|
| - contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
|
| - tryAgain, &test, opp);
|
| + contourWinding = contourRangeCheckY(contourList, currentPtr, indexPtr, endIndexPtr,
|
| + tHit, hitDx, tryAgain, &test, opp);
|
| if (contourWinding != SK_MinS32 || *tryAgain) {
|
| return contourWinding;
|
| }
|
| + if (*currentPtr && (*currentPtr)->isVertical()) {
|
| + *onlyVertical = true;
|
| + return contourWinding;
|
| + }
|
| test /= 2;
|
| } while (!approximately_negative(test));
|
| - SkASSERT(0); // should be OK to comment out, but interested when this hits
|
| + SkASSERT(0); // FIXME: incomplete functionality
|
| return contourWinding;
|
| }
|
|
|
| @@ -296,30 +317,34 @@ static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
|
|
|
| SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr,
|
| - int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool firstPass) {
|
| - SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
|
| + int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical,
|
| + bool firstPass) {
|
| + SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
|
| done, firstPass);
|
| if (!current) {
|
| return NULL;
|
| }
|
| - const int index = *indexPtr;
|
| + const int startIndex = *indexPtr;
|
| const int endIndex = *endIndexPtr;
|
| if (*firstContour) {
|
| - current->initWinding(index, endIndex, angleIncludeType);
|
| + current->initWinding(startIndex, endIndex, angleIncludeType);
|
| *firstContour = false;
|
| return current;
|
| }
|
| - int minIndex = SkMin32(index, endIndex);
|
| + int minIndex = SkMin32(startIndex, endIndex);
|
| int sumWinding = current->windSum(minIndex);
|
| - if (sumWinding != SK_MinS32) {
|
| - return current;
|
| - }
|
| - SkASSERT(current->windSum(SkMin32(index, endIndex)) == SK_MinS32);
|
| - const SkOpSpan& span = current->span(endIndex);
|
| - if ((index < endIndex ? span.fFromAngleIndex : span.fToAngleIndex) < 0) {
|
| - current->addSimpleAngle(endIndex);
|
| + if (sumWinding == SK_MinS32) {
|
| + int index = endIndex;
|
| + int oIndex = startIndex;
|
| + do {
|
| + const SkOpSpan& span = current->span(index);
|
| + if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) {
|
| + current->addSimpleAngle(index);
|
| + }
|
| + sumWinding = current->computeSum(oIndex, index, angleIncludeType);
|
| + SkTSwap(index, oIndex);
|
| + } while (sumWinding == SK_MinS32 && index == startIndex);
|
| }
|
| - sumWinding = current->computeSum(index, endIndex, angleIncludeType);
|
| if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) {
|
| return current;
|
| }
|
| @@ -340,7 +365,10 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
|
| tryAgain = false;
|
| contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit,
|
| - &hitDx, &tryAgain, false);
|
| + &hitDx, &tryAgain, onlyVertical, false);
|
| + if (*onlyVertical) {
|
| + return current;
|
| + }
|
| if (tryAgain) {
|
| continue;
|
| }
|
| @@ -348,7 +376,7 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| break;
|
| }
|
| oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit,
|
| - &hitOppDx, &tryAgain, true);
|
| + &hitOppDx, &tryAgain, NULL, true);
|
| } while (tryAgain);
|
| current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding,
|
| hitOppDx);
|
| @@ -387,14 +415,15 @@ static void checkEnds(SkTArray<SkOpContour*, true>* contourList) {
|
| }
|
| }
|
|
|
| -static void checkMultiples(SkTArray<SkOpContour*, true>* contourList) {
|
| - // it's hard to determine if the end of a cubic or conic nearly intersects another curve.
|
| - // instead, look to see if the connecting curve intersected at that same end.
|
| +static bool checkMultiples(SkTArray<SkOpContour*, true>* contourList) {
|
| + bool hasMultiples = false;
|
| int contourCount = (*contourList).count();
|
| for (int cTest = 0; cTest < contourCount; ++cTest) {
|
| SkOpContour* contour = (*contourList)[cTest];
|
| contour->checkMultiples();
|
| + hasMultiples |= contour->hasMultiples();
|
| }
|
| + return hasMultiples;
|
| }
|
|
|
| // A small interval of a pair of curves may collapse to lines for each, triggering coincidence
|
| @@ -675,12 +704,17 @@ bool HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) {
|
| SkOpContour::debugShowWindingValues(contourList);
|
| #endif
|
| fixOtherTIndex(contourList);
|
| - checkEnds(contourList);
|
| - checkMultiples(contourList);
|
| - checkDuplicates(contourList);
|
| - checkTiny(contourList);
|
| - checkSmall(contourList);
|
| - joinCoincidence(contourList);
|
| + checkEnds(contourList); // check if connecting curve intersected at the same end
|
| + bool hasM = checkMultiples(contourList); // check if intersections agree on t and point values
|
| + SkTDArray<SkOpSegment::AlignedSpan> aligned;
|
| + if (hasM) {
|
| + alignMultiples(contourList, &aligned); // align pairs of identical points
|
| + alignCoincidence(contourList, aligned);
|
| + }
|
| + checkDuplicates(contourList); // check if spans have the same number on the other end
|
| + checkTiny(contourList); // if pair have the same end points, mark them as parallel
|
| + checkSmall(contourList); // a pair of curves with a small span may turn into coincident lines
|
| + joinCoincidence(contourList); // join curves that connect to a coincident pair
|
| sortSegments(contourList);
|
| if (!calcAngles(contourList)) {
|
| return false;
|
|
|