fix minor skp-found bugs
remove globals from pathops_unittest BUG=skia:2460 TBR=mtklein Author: caryclark@google.com Review URL: https://codereview.chromium.org/239563004 git-svn-id: http://skia.googlecode.com/svn/trunk@14378 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
e1ba93ee01
commit
8cb1daaa1e
@ -24,6 +24,7 @@
|
||||
'sources': [
|
||||
'../tests/PathOpsAngleIdeas.cpp',
|
||||
'../tests/PathOpsDebug.cpp',
|
||||
'../tests/PathOpsOpLoopThreadedTest.cpp',
|
||||
'../tests/PathOpsSkpClipTest.cpp',
|
||||
'../tests/Test.cpp',
|
||||
'../tests/skia_test.cpp',
|
||||
|
@ -494,7 +494,18 @@ int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) {
|
||||
cubicNearEnd(c1, false, c2, c2Bounds);
|
||||
}
|
||||
if (!(exactEndBits & 8)) {
|
||||
if (selfIntersect && fUsed) {
|
||||
return fUsed;
|
||||
}
|
||||
cubicNearEnd(c1, true, c2, c2Bounds);
|
||||
if (selfIntersect && fUsed && ((approximately_less_than_zero(fT[0][0])
|
||||
&& approximately_less_than_zero(fT[1][0]))
|
||||
|| (approximately_greater_than_one(fT[0][0])
|
||||
&& approximately_greater_than_one(fT[1][0])))) {
|
||||
SkASSERT(fUsed == 1);
|
||||
fUsed = 0;
|
||||
return fUsed;
|
||||
}
|
||||
}
|
||||
if (!selfIntersect) {
|
||||
SkDRect c1Bounds;
|
||||
|
@ -292,7 +292,7 @@ int SkIntersections::vertical(const SkDLine& line, double x) {
|
||||
|
||||
int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
|
||||
double x, bool flipped) {
|
||||
fMax = 2;
|
||||
fMax = 3; // cleanup parallel lines will bring this back line
|
||||
// see if end points intersect the opposite line
|
||||
double t;
|
||||
SkDPoint topPt = { x, top };
|
||||
@ -344,6 +344,7 @@ int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
|
||||
}
|
||||
}
|
||||
cleanUpParallelLines(result == 2);
|
||||
SkASSERT(fUsed <= 2);
|
||||
return fUsed;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ public:
|
||||
, fLine(l)
|
||||
, fIntersections(i)
|
||||
, fAllowNear(true) {
|
||||
i->setMax(2);
|
||||
i->setMax(3); // allow short partial coincidence plus discrete intersection
|
||||
}
|
||||
|
||||
void allowNear(bool allow) {
|
||||
@ -331,6 +331,9 @@ protected:
|
||||
*pt = fLine[1];
|
||||
*lineT = 1;
|
||||
}
|
||||
if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) {
|
||||
return false;
|
||||
}
|
||||
if (gridPt == fQuad[0].asSkPoint()) {
|
||||
*pt = fQuad[0];
|
||||
*quadT = 0;
|
||||
|
@ -164,7 +164,7 @@ public:
|
||||
quad.set(a);
|
||||
SkDLine line;
|
||||
line.set(b);
|
||||
fMax = 2;
|
||||
fMax = 3; // 2; permit small coincident segment + non-coincident intersection
|
||||
return intersect(quad, line);
|
||||
}
|
||||
|
||||
|
@ -321,9 +321,11 @@ recomputeSector:
|
||||
fUnorderable = true;
|
||||
return false;
|
||||
}
|
||||
int saveEnd = fEnd;
|
||||
fEnd = checkEnd - step;
|
||||
setSpans();
|
||||
setSector();
|
||||
fEnd = saveEnd;
|
||||
return !fUnorderable;
|
||||
}
|
||||
|
||||
@ -658,6 +660,9 @@ void SkOpAngle::insert(SkOpAngle* angle) {
|
||||
}
|
||||
SkOpAngle* next = fNext;
|
||||
if (next->fNext == this) {
|
||||
if (angle->overlap(*this)) {
|
||||
return;
|
||||
}
|
||||
if (singleton || angle->after(this)) {
|
||||
this->fNext = angle;
|
||||
angle->fNext = next;
|
||||
@ -671,6 +676,9 @@ void SkOpAngle::insert(SkOpAngle* angle) {
|
||||
SkOpAngle* last = this;
|
||||
do {
|
||||
SkASSERT(last->fNext == next);
|
||||
if (angle->overlap(*last) || angle->overlap(*next)) {
|
||||
return;
|
||||
}
|
||||
if (angle->after(last)) {
|
||||
last->fNext = angle;
|
||||
angle->fNext = next;
|
||||
@ -701,6 +709,33 @@ SkOpSpan* SkOpAngle::lastMarked() const {
|
||||
return fLastMarked;
|
||||
}
|
||||
|
||||
bool SkOpAngle::loopContains(const SkOpAngle& test) const {
|
||||
if (!fNext) {
|
||||
return false;
|
||||
}
|
||||
const SkOpAngle* first = this;
|
||||
const SkOpAngle* loop = this;
|
||||
const SkOpSegment* tSegment = test.fSegment;
|
||||
double tStart = tSegment->span(test.fStart).fT;
|
||||
double tEnd = tSegment->span(test.fEnd).fT;
|
||||
do {
|
||||
const SkOpSegment* lSegment = loop->fSegment;
|
||||
// FIXME : use precisely_equal ? or compare points exactly ?
|
||||
if (lSegment != tSegment) {
|
||||
continue;
|
||||
}
|
||||
double lStart = lSegment->span(loop->fStart).fT;
|
||||
if (lStart != tEnd) {
|
||||
continue;
|
||||
}
|
||||
double lEnd = lSegment->span(loop->fEnd).fT;
|
||||
if (lEnd == tStart) {
|
||||
return true;
|
||||
}
|
||||
} while ((loop = loop->fNext) != first);
|
||||
return false;
|
||||
}
|
||||
|
||||
int SkOpAngle::loopCount() const {
|
||||
int count = 0;
|
||||
const SkOpAngle* first = this;
|
||||
@ -813,6 +848,23 @@ unorderable:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkOpAngle::overlap(const SkOpAngle& other) const {
|
||||
int min = SkTMin(fStart, fEnd);
|
||||
const SkOpSpan& span = fSegment->span(min);
|
||||
const SkOpSegment* oSeg = other.fSegment;
|
||||
int oMin = SkTMin(other.fStart, other.fEnd);
|
||||
const SkOpSpan& oSpan = oSeg->span(oMin);
|
||||
if (!span.fSmall && !oSpan.fSmall) {
|
||||
return false;
|
||||
}
|
||||
if (fSegment->span(fStart).fPt != oSeg->span(other.fStart).fPt) {
|
||||
return false;
|
||||
}
|
||||
// see if small span is contained by opposite span
|
||||
return span.fSmall ? oSeg->containsPt(fSegment->span(fEnd).fPt, other.fEnd, other.fStart)
|
||||
: fSegment->containsPt(oSeg->span(other.fEnd).fPt, fEnd, fStart);
|
||||
}
|
||||
|
||||
// OPTIMIZE: if this shows up in a profile, add a previous pointer
|
||||
// as is, this should be rarely called
|
||||
SkOpAngle* SkOpAngle::previous() const {
|
||||
|
@ -24,6 +24,7 @@ public:
|
||||
kBinaryOpp,
|
||||
};
|
||||
|
||||
|
||||
int end() const {
|
||||
return fEnd;
|
||||
}
|
||||
@ -37,6 +38,7 @@ public:
|
||||
void insert(SkOpAngle* );
|
||||
bool isHorizontal() const;
|
||||
SkOpSpan* lastMarked() const;
|
||||
bool loopContains(const SkOpAngle& ) const;
|
||||
int loopCount() const;
|
||||
void markStops();
|
||||
bool merge(SkOpAngle* );
|
||||
@ -104,6 +106,7 @@ private:
|
||||
double midT() const;
|
||||
bool oppositePlanes(const SkOpAngle& rh) const;
|
||||
bool orderable(const SkOpAngle& rh) const; // false == this < rh ; true == this > rh
|
||||
bool overlap(const SkOpAngle& test) const;
|
||||
void setCurveHullSweep();
|
||||
void setSector();
|
||||
void setSpans();
|
||||
|
@ -211,9 +211,12 @@ void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coinciden
|
||||
}
|
||||
bool swapStart = startT > endT;
|
||||
bool swapOther = oStartT > oEndT;
|
||||
const SkPoint* startPt = &coincidence.fPts[0];
|
||||
const SkPoint* endPt = &coincidence.fPts[1];
|
||||
if (swapStart) {
|
||||
SkTSwap<double>(startT, endT);
|
||||
SkTSwap<double>(oStartT, oEndT);
|
||||
SkTSwap(startT, endT);
|
||||
SkTSwap(oStartT, oEndT);
|
||||
SkTSwap(startPt, endPt);
|
||||
}
|
||||
bool cancel = swapOther != swapStart;
|
||||
int step = swapStart ? -1 : 1;
|
||||
@ -222,17 +225,18 @@ void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coinciden
|
||||
if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatchStart == 0)) {
|
||||
bool added = false;
|
||||
if (oMatchStart != 0) {
|
||||
added = thisOne.joinCoincidence(&other, oMatchStart, oStep, cancel);
|
||||
const SkPoint& oMatchStartPt = cancel ? *endPt : *startPt;
|
||||
added = thisOne.joinCoincidence(&other, oMatchStart, oMatchStartPt, oStep, cancel);
|
||||
}
|
||||
if (!cancel && startT != 0 && !added) {
|
||||
(void) other.joinCoincidence(&thisOne, startT, step, cancel);
|
||||
(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, -step, cancel);
|
||||
(void) other.joinCoincidence(&thisOne, endT, *endPt, -step, cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,7 +333,7 @@ void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY,
|
||||
continue;
|
||||
}
|
||||
fDone = false;
|
||||
SkPoint testXY = testSegment->activeLeftTop(true, NULL);
|
||||
SkPoint testXY = testSegment->activeLeftTop(NULL);
|
||||
if (*topStart) {
|
||||
if (testXY.fY < topLeft.fY) {
|
||||
continue;
|
||||
|
@ -13,7 +13,7 @@ void SkOpEdgeBuilder::init() {
|
||||
fOperand = false;
|
||||
fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
|
||||
: kWinding_PathOpsMask;
|
||||
#ifdef SK_DEBUG
|
||||
#if defined(SK_DEBUG) || !FORCE_RELEASE
|
||||
SkPathOpsDebug::gContourID = 0;
|
||||
SkPathOpsDebug::gSegmentID = 0;
|
||||
#endif
|
||||
|
@ -70,16 +70,12 @@ const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end,
|
||||
int next = nextExactSpan(index, 1);
|
||||
if (next > 0) {
|
||||
const SkOpSpan& upSpan = fTs[index];
|
||||
if (upSpan.fUnsortableStart) {
|
||||
*sortable = false;
|
||||
return NULL;
|
||||
}
|
||||
if (upSpan.fWindValue || upSpan.fOppValue) {
|
||||
if (*end < 0) {
|
||||
*start = index;
|
||||
*end = next;
|
||||
}
|
||||
if (!upSpan.fDone && !upSpan.fUnsortableEnd) {
|
||||
if (!upSpan.fDone) {
|
||||
if (upSpan.fWindSum != SK_MinS32) {
|
||||
return spanToAngle(index, next);
|
||||
}
|
||||
@ -93,10 +89,6 @@ const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end,
|
||||
// edge leading into junction
|
||||
if (prev >= 0) {
|
||||
const SkOpSpan& downSpan = fTs[prev];
|
||||
if (downSpan.fUnsortableEnd) {
|
||||
*sortable = false;
|
||||
return NULL;
|
||||
}
|
||||
if (downSpan.fWindValue || downSpan.fOppValue) {
|
||||
if (*end < 0) {
|
||||
*start = index;
|
||||
@ -123,19 +115,15 @@ const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end,
|
||||
return other->activeAngleInner(oIndex, start, end, done, sortable);
|
||||
}
|
||||
|
||||
SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
|
||||
SkPoint SkOpSegment::activeLeftTop(int* firstT) const {
|
||||
SkASSERT(!done());
|
||||
SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
|
||||
int count = fTs.count();
|
||||
// see if either end is not done since we want smaller Y of the pair
|
||||
bool lastDone = true;
|
||||
bool lastUnsortable = false;
|
||||
double lastT = -1;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
const SkOpSpan& span = fTs[index];
|
||||
if (onlySortable && (span.fUnsortableStart || lastUnsortable)) {
|
||||
goto next;
|
||||
}
|
||||
if (span.fDone && lastDone) {
|
||||
goto next;
|
||||
}
|
||||
@ -164,7 +152,6 @@ SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
|
||||
}
|
||||
next:
|
||||
lastDone = span.fDone;
|
||||
lastUnsortable = span.fUnsortableEnd;
|
||||
}
|
||||
return topPt;
|
||||
}
|
||||
@ -345,16 +332,19 @@ void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
|
||||
do {
|
||||
workPt = &fTs[++tIndex].fPt;
|
||||
} while (nextPt == *workPt);
|
||||
const SkPoint* oWorkPt;
|
||||
do {
|
||||
workPt = &other->fTs[++oIndex].fPt;
|
||||
} while (nextPt == *workPt);
|
||||
oWorkPt = &other->fTs[++oIndex].fPt;
|
||||
} while (nextPt == *oWorkPt);
|
||||
nextPt = *workPt;
|
||||
double tStart = fTs[tIndex].fT;
|
||||
double oStart = other->fTs[oIndex].fT;
|
||||
if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
|
||||
break;
|
||||
}
|
||||
addTPair(tStart, other, oStart, false, nextPt);
|
||||
if (*workPt == *oWorkPt) {
|
||||
addTPair(tStart, other, oStart, false, nextPt);
|
||||
}
|
||||
} while (endPt != nextPt);
|
||||
}
|
||||
|
||||
@ -618,8 +608,6 @@ int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
|
||||
span->fLoop = false;
|
||||
span->fSmall = false;
|
||||
span->fTiny = false;
|
||||
span->fUnsortableStart = false;
|
||||
span->fUnsortableEnd = false;
|
||||
int less = -1;
|
||||
// find range of spans with nearly the same point as this one
|
||||
while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
|
||||
@ -834,18 +822,27 @@ bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
|
||||
aligned = true;
|
||||
}
|
||||
double oT = oSpan->fT;
|
||||
if (oT == 0 || oT == 1) {
|
||||
if (oT == 0) {
|
||||
return aligned;
|
||||
}
|
||||
int oStart = other->nextSpan(oIndex, -1) + 1;
|
||||
int oEnd = other->nextSpan(oIndex, 1);
|
||||
oSpan = &other->fTs[oStart];
|
||||
int otherIndex = oStart;
|
||||
if (oT == 1) {
|
||||
if (aligned) {
|
||||
while (oSpan->fPt == thisPt && oSpan->fT != 1) {
|
||||
oSpan->fTiny = true;
|
||||
++oSpan;
|
||||
}
|
||||
}
|
||||
return aligned;
|
||||
}
|
||||
oT = oSpan->fT;
|
||||
int oEnd = other->nextSpan(oIndex, 1);
|
||||
bool oAligned = false;
|
||||
if (oSpan->fPt != thisPt) {
|
||||
oAligned |= other->alignSpan(oStart, oT, thisPt);
|
||||
}
|
||||
int otherIndex = oStart;
|
||||
while (++otherIndex < oEnd) {
|
||||
SkOpSpan* oNextSpan = &other->fTs[otherIndex];
|
||||
if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) {
|
||||
@ -1352,14 +1349,17 @@ void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne
|
||||
nextAngle->setLastMarked(last);
|
||||
}
|
||||
|
||||
void SkOpSegment::constructLine(SkPoint shortLine[2]) {
|
||||
addLine(shortLine, false, false);
|
||||
addT(NULL, shortLine[0], 0);
|
||||
addT(NULL, shortLine[1], 1);
|
||||
addStartSpan(1);
|
||||
addEndSpan(1);
|
||||
SkOpAngle& angle = fAngles.push_back();
|
||||
angle.set(this, 0, 1);
|
||||
bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
|
||||
int step = index < endIndex ? 1 : -1;
|
||||
do {
|
||||
const SkOpSpan& span = this->span(index);
|
||||
if (span.fPt == pt) {
|
||||
const SkOpSpan& endSpan = this->span(endIndex);
|
||||
return span.fT == endSpan.fT && pt != endSpan.fPt;
|
||||
}
|
||||
index += step;
|
||||
} while (index != endIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
|
||||
@ -1923,7 +1923,7 @@ nextSmallCheck:
|
||||
missing.fPt)) {
|
||||
continue;
|
||||
}
|
||||
int otherTIndex = missingOther->findT(missing.fOtherT, missing.fSegment);
|
||||
int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment);
|
||||
const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
|
||||
if (otherSpan.fSmall) {
|
||||
const SkOpSpan* nextSpan = &otherSpan;
|
||||
@ -1955,7 +1955,9 @@ nextSmallCheck:
|
||||
void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
|
||||
SkTArray<MissingSpan, true>* checkMultiple) {
|
||||
SkASSERT(span.fSmall);
|
||||
SkASSERT(span.fWindValue);
|
||||
if (0 && !span.fWindValue) {
|
||||
return;
|
||||
}
|
||||
SkASSERT(&span < fTs.end() - 1);
|
||||
const SkOpSpan* next = &span + 1;
|
||||
SkASSERT(!next->fSmall || checkMultiple);
|
||||
@ -2271,11 +2273,13 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
||||
bool sortable = calcWinding != SK_NaN32;
|
||||
if (!sortable) {
|
||||
*unsortable = true;
|
||||
markDoneBinary(SkMin32(startIndex, endIndex));
|
||||
return NULL;
|
||||
}
|
||||
SkOpAngle* angle = spanToAngle(end, startIndex);
|
||||
if (angle->unorderable()) {
|
||||
*unsortable = true;
|
||||
markDoneBinary(SkMin32(startIndex, endIndex));
|
||||
return NULL;
|
||||
}
|
||||
#if DEBUG_SORT
|
||||
@ -2283,6 +2287,11 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
||||
angle->debugLoop();
|
||||
#endif
|
||||
int sumMiWinding = updateWinding(endIndex, startIndex);
|
||||
if (sumMiWinding == SK_MinS32) {
|
||||
*unsortable = true;
|
||||
markDoneBinary(SkMin32(startIndex, endIndex));
|
||||
return NULL;
|
||||
}
|
||||
int sumSuWinding = updateOppWinding(endIndex, startIndex);
|
||||
if (operand()) {
|
||||
SkTSwap<int>(sumMiWinding, sumSuWinding);
|
||||
@ -2302,6 +2311,7 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
|
||||
if (!foundAngle || (foundDone && activeCount & 1)) {
|
||||
if (nextSegment->isTiny(nextAngle)) {
|
||||
*unsortable = true;
|
||||
markDoneBinary(SkMin32(startIndex, endIndex));
|
||||
return NULL;
|
||||
}
|
||||
foundAngle = nextAngle;
|
||||
@ -2393,6 +2403,7 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
||||
bool sortable = calcWinding != SK_NaN32;
|
||||
if (!sortable) {
|
||||
*unsortable = true;
|
||||
markDoneUnary(SkMin32(startIndex, endIndex));
|
||||
return NULL;
|
||||
}
|
||||
SkOpAngle* angle = spanToAngle(end, startIndex);
|
||||
@ -2415,6 +2426,7 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
||||
if (!foundAngle || (foundDone && activeCount & 1)) {
|
||||
if (nextSegment->isTiny(nextAngle)) {
|
||||
*unsortable = true;
|
||||
markDoneUnary(SkMin32(startIndex, endIndex));
|
||||
return NULL;
|
||||
}
|
||||
foundAngle = nextAngle;
|
||||
@ -2433,7 +2445,6 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
|
||||
SkOpSpan* last = nextAngle->lastMarked();
|
||||
if (last) {
|
||||
SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
|
||||
// assert here that span isn't already in array
|
||||
*chase->append() = last;
|
||||
#if DEBUG_WINDING
|
||||
SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
|
||||
@ -2584,7 +2595,7 @@ int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SkOpSegment::findT(double t, const SkOpSegment* match) const {
|
||||
int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const {
|
||||
int count = this->count();
|
||||
for (int index = 0; index < count; ++index) {
|
||||
const SkOpSpan& span = fTs[index];
|
||||
@ -2592,18 +2603,28 @@ int SkOpSegment::findT(double t, const SkOpSegment* match) const {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
// Usually, the pair of ts are an exact match. It's possible that the t values have
|
||||
// been adjusted to make multiple intersections align. In this rare case, look for a
|
||||
// matching point / match pair instead.
|
||||
for (int index = 0; index < count; ++index) {
|
||||
const SkOpSpan& span = fTs[index];
|
||||
if (span.fPt == pt && span.fOther == match) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
SkASSERT(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable) {
|
||||
SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
|
||||
bool firstPass) {
|
||||
// iterate through T intersections and return topmost
|
||||
// topmost tangent from y-min to first pt is closer to horizontal
|
||||
SkASSERT(!done());
|
||||
int firstT = -1;
|
||||
/* SkPoint topPt = */ activeLeftTop(true, &firstT);
|
||||
/* SkPoint topPt = */ activeLeftTop(&firstT);
|
||||
if (firstT < 0) {
|
||||
*unsortable = true;
|
||||
*unsortable = !firstPass;
|
||||
firstT = 0;
|
||||
while (fTs[firstT].fDone) {
|
||||
SkASSERT(firstT < fTs.count());
|
||||
@ -2655,14 +2676,24 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
|
||||
#endif
|
||||
// skip edges that have already been processed
|
||||
angle = firstAngle;
|
||||
SkOpSegment* leftSegment;
|
||||
SkOpSegment* leftSegment = NULL;
|
||||
bool looped = false;
|
||||
do {
|
||||
// SkASSERT(!angle->unsortable());
|
||||
leftSegment = angle->segment();
|
||||
*tIndexPtr = angle->end();
|
||||
*endIndexPtr = angle->start();
|
||||
*unsortable = angle->unorderable();
|
||||
if (firstPass || !*unsortable) {
|
||||
leftSegment = angle->segment();
|
||||
*tIndexPtr = angle->end();
|
||||
*endIndexPtr = angle->start();
|
||||
if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
angle = angle->next();
|
||||
} while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone);
|
||||
looped = true;
|
||||
} while (angle != firstAngle);
|
||||
if (angle == firstAngle && looped) {
|
||||
return NULL;
|
||||
}
|
||||
if (leftSegment->verb() >= SkPath::kQuad_Verb) {
|
||||
const int tIndex = *tIndexPtr;
|
||||
const int endIndex = *endIndexPtr;
|
||||
@ -2670,8 +2701,9 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
|
||||
bool swap = !leftSegment->monotonicInY(tIndex, endIndex)
|
||||
&& !leftSegment->serpentine(tIndex, endIndex);
|
||||
#if DEBUG_SWAP_TOP
|
||||
SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__,
|
||||
swap,
|
||||
SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n",
|
||||
__FUNCTION__,
|
||||
swap, leftSegment->debugInflections(tIndex, endIndex),
|
||||
leftSegment->serpentine(tIndex, endIndex),
|
||||
leftSegment->controlsContainedByEnds(tIndex, endIndex),
|
||||
leftSegment->monotonicInY(tIndex, endIndex));
|
||||
@ -2840,13 +2872,6 @@ bool SkOpSegment::isSimple(int end) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SkOpSegment::isSmall(const SkOpAngle* angle) const {
|
||||
int start = angle->start();
|
||||
int end = angle->end();
|
||||
const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
|
||||
return mSpan.fSmall;
|
||||
}
|
||||
|
||||
bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
|
||||
int start = angle->start();
|
||||
int end = angle->end();
|
||||
@ -2863,8 +2888,9 @@ bool SkOpSegment::isTiny(int index) const {
|
||||
// if both are active, look to see if they both the connect to another coincident pair
|
||||
// if at least one is a line, then make the pair coincident
|
||||
// if neither is a line, test for coincidence
|
||||
bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel) {
|
||||
int otherTIndex = other->findT(otherT, this);
|
||||
bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt,
|
||||
int step, bool cancel) {
|
||||
int otherTIndex = other->findT(otherT, otherPt, this);
|
||||
int next = other->nextExactSpan(otherTIndex, step);
|
||||
int otherMin = SkMin32(otherTIndex, next);
|
||||
int otherWind = other->span(otherMin).fWindValue;
|
||||
@ -3106,7 +3132,9 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
|
||||
debugShowNewWinding(funName, span, winding);
|
||||
#endif
|
||||
SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
|
||||
SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
|
||||
#if DEBUG_LIMIT_WIND_SUM
|
||||
SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
|
||||
#endif
|
||||
span.fWindSum = winding;
|
||||
return &span;
|
||||
}
|
||||
@ -3121,10 +3149,14 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
|
||||
debugShowNewWinding(funName, span, winding, oppWinding);
|
||||
#endif
|
||||
SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
|
||||
SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum);
|
||||
#if DEBUG_LIMIT_WIND_SUM
|
||||
SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
|
||||
#endif
|
||||
span.fWindSum = winding;
|
||||
SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
|
||||
SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum);
|
||||
#if DEBUG_LIMIT_WIND_SUM
|
||||
SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM);
|
||||
#endif
|
||||
span.fOppSum = oppWinding;
|
||||
debugValidate();
|
||||
return &span;
|
||||
@ -3157,9 +3189,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const {
|
||||
}
|
||||
|
||||
bool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
|
||||
if (fVerb == SkPath::kLine_Verb) {
|
||||
return false;
|
||||
}
|
||||
SkASSERT(fVerb != SkPath::kLine_Verb);
|
||||
if (fVerb == SkPath::kQuad_Verb) {
|
||||
SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
|
||||
return dst.monotonicInY();
|
||||
@ -3210,33 +3240,6 @@ SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
|
||||
return &span;
|
||||
}
|
||||
|
||||
// note that just because a span has one end that is unsortable, that's
|
||||
// not enough to mark it done. The other end may be sortable, allowing the
|
||||
// span to be added.
|
||||
// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends
|
||||
void SkOpSegment::markUnsortable(int start, int end) {
|
||||
SkOpSpan* span = &fTs[start];
|
||||
if (start < end) {
|
||||
#if DEBUG_UNSORTABLE
|
||||
debugShowNewWinding(__FUNCTION__, *span, 0);
|
||||
#endif
|
||||
span->fUnsortableStart = true;
|
||||
} else {
|
||||
--span;
|
||||
#if DEBUG_UNSORTABLE
|
||||
debugShowNewWinding(__FUNCTION__, *span, 0);
|
||||
#endif
|
||||
span->fUnsortableEnd = true;
|
||||
}
|
||||
if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) {
|
||||
debugValidate();
|
||||
return;
|
||||
}
|
||||
span->fDone = true;
|
||||
fDoneSpans++;
|
||||
debugValidate();
|
||||
}
|
||||
|
||||
void SkOpSegment::markWinding(int index, int winding) {
|
||||
// SkASSERT(!done());
|
||||
SkASSERT(winding);
|
||||
@ -3426,8 +3429,10 @@ void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int*
|
||||
*oppMaxWinding = *sumSuWinding;
|
||||
*oppSumWinding = *sumSuWinding -= oppDeltaSum;
|
||||
}
|
||||
SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
|
||||
SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum);
|
||||
#if DEBUG_LIMIT_WIND_SUM
|
||||
SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
|
||||
SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
|
||||
@ -3435,7 +3440,9 @@ void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
|
||||
int deltaSum = spanSign(index, endIndex);
|
||||
*maxWinding = *sumMiWinding;
|
||||
*sumWinding = *sumMiWinding -= deltaSum;
|
||||
SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum);
|
||||
#if DEBUG_LIMIT_WIND_SUM
|
||||
SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkOpSegment::sortAngles() {
|
||||
@ -3494,7 +3501,10 @@ void SkOpSegment::sortAngles() {
|
||||
wroteAfterHeader = true;
|
||||
}
|
||||
#endif
|
||||
baseAngle->insert(&other->angle(otherAngleIndex));
|
||||
SkOpAngle* oAngle = &other->angle(otherAngleIndex);
|
||||
if (!oAngle->loopContains(*baseAngle)) {
|
||||
baseAngle->insert(oAngle);
|
||||
}
|
||||
}
|
||||
otherAngleIndex = oSpan.fToAngleIndex;
|
||||
if (otherAngleIndex >= 0) {
|
||||
@ -3505,7 +3515,10 @@ void SkOpSegment::sortAngles() {
|
||||
wroteAfterHeader = true;
|
||||
}
|
||||
#endif
|
||||
baseAngle->insert(&other->angle(otherAngleIndex));
|
||||
SkOpAngle* oAngle = &other->angle(otherAngleIndex);
|
||||
if (!oAngle->loopContains(*baseAngle)) {
|
||||
baseAngle->insert(oAngle);
|
||||
}
|
||||
}
|
||||
if (++index == spanCount) {
|
||||
break;
|
||||
@ -3673,6 +3686,9 @@ int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
|
||||
int SkOpSegment::updateWinding(int index, int endIndex) const {
|
||||
int lesser = SkMin32(index, endIndex);
|
||||
int winding = windSum(lesser);
|
||||
if (winding == SK_MinS32) {
|
||||
return winding;
|
||||
}
|
||||
int spanWinding = spanSign(index, endIndex);
|
||||
if (winding && UseInnerWinding(winding - spanWinding, winding)
|
||||
&& winding != SK_MaxS32) {
|
||||
|
@ -48,8 +48,6 @@ public:
|
||||
return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
|
||||
}
|
||||
|
||||
void constructLine(SkPoint shortLine[2]);
|
||||
|
||||
int count() const {
|
||||
return fTs.count();
|
||||
}
|
||||
@ -193,11 +191,6 @@ public:
|
||||
return const_cast<SkOpAngle*>(cAngle);
|
||||
}
|
||||
|
||||
// OPTIMIZATION: mark as debugging only if used solely by tests
|
||||
const SkTDArray<SkOpSpan>& spans() const {
|
||||
return fTs;
|
||||
}
|
||||
|
||||
int spanSign(const SkOpAngle* angle) const {
|
||||
SkASSERT(angle->segment() == this);
|
||||
return spanSign(angle->start(), angle->end());
|
||||
@ -219,10 +212,6 @@ public:
|
||||
return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
|
||||
}
|
||||
|
||||
bool unsortable(int index) const {
|
||||
return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
|
||||
}
|
||||
|
||||
void updatePts(const SkPoint pts[]) {
|
||||
fPts = pts;
|
||||
}
|
||||
@ -267,7 +256,7 @@ public:
|
||||
|
||||
const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done,
|
||||
bool* sortable) const;
|
||||
SkPoint activeLeftTop(bool onlySortable, int* firstT) const;
|
||||
SkPoint activeLeftTop(int* firstT) const;
|
||||
bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
|
||||
bool activeWinding(int index, int endIndex);
|
||||
void addCubic(const SkPoint pts[4], bool operand, bool evenOdd);
|
||||
@ -297,6 +286,7 @@ public:
|
||||
bool checkSmall(int index) const;
|
||||
void checkTiny();
|
||||
int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType);
|
||||
bool containsPt(const SkPoint& , int index, int endIndex) const;
|
||||
int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething,
|
||||
double mid, bool opp, bool current) const;
|
||||
bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd,
|
||||
@ -307,16 +297,16 @@ public:
|
||||
bool* unsortable);
|
||||
SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable);
|
||||
int findExactT(double t, const SkOpSegment* ) const;
|
||||
int findT(double t, const SkOpSegment* ) const;
|
||||
SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable);
|
||||
int findT(double t, const SkPoint& , const SkOpSegment* ) const;
|
||||
SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool firstPass);
|
||||
void fixOtherTIndex();
|
||||
void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType);
|
||||
void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
|
||||
SkScalar hitOppDx);
|
||||
bool isMissing(double startT, const SkPoint& pt) const;
|
||||
bool isSmall(const SkOpAngle* angle) const;
|
||||
bool isTiny(const SkOpAngle* angle) const;
|
||||
bool joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel);
|
||||
bool joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, int step,
|
||||
bool cancel);
|
||||
SkOpSpan* markAndChaseDoneBinary(int index, int endIndex);
|
||||
SkOpSpan* markAndChaseDoneUnary(int index, int endIndex);
|
||||
SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding);
|
||||
@ -361,6 +351,7 @@ public:
|
||||
#if DEBUG_SHOW_WINDING
|
||||
int debugShowWindingValues(int slotCount, int ofInterest) const;
|
||||
#endif
|
||||
const SkTDArray<SkOpSpan>& debugSpans() const;
|
||||
void debugValidate() const;
|
||||
// available to testing only
|
||||
void dumpAngles() const;
|
||||
@ -439,7 +430,6 @@ private:
|
||||
SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding);
|
||||
void markWinding(int index, int winding);
|
||||
void markWinding(int index, int winding, int oppWinding);
|
||||
void markUnsortable(int start, int end);
|
||||
bool monotonicInY(int tStart, int tEnd) const;
|
||||
|
||||
bool multipleEnds() const {
|
||||
@ -490,6 +480,9 @@ private:
|
||||
#if DEBUG_ANGLE
|
||||
void debugCheckPointsEqualish(int tStart, int tEnd) const;
|
||||
#endif
|
||||
#if DEBUG_SWAP_TOP
|
||||
int debugInflections(int index, int endIndex) const;
|
||||
#endif
|
||||
#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
|
||||
void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding);
|
||||
void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding);
|
||||
|
@ -28,8 +28,6 @@ struct SkOpSpan {
|
||||
bool fLoop; // set when a cubic loops back to this point
|
||||
bool fSmall; // if set, consecutive points are almost equal
|
||||
bool fTiny; // if set, consecutive points are equal but consecutive ts are not precisely equal
|
||||
bool fUnsortableStart; // set when start is part of an unsortable pair
|
||||
bool fUnsortableEnd; // set when end is part of an unsortable pair
|
||||
|
||||
// available to testing only
|
||||
const SkOpSegment* debugToSegment(ptrdiff_t* ) const;
|
||||
|
@ -206,7 +206,7 @@ void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) {
|
||||
|
||||
static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
||||
int* index, int* endIndex, SkPoint* topLeft, bool* unsortable,
|
||||
bool* done, bool onlySortable) {
|
||||
bool* done, bool firstPass) {
|
||||
SkOpSegment* result;
|
||||
const SkOpSegment* lastTopStart = NULL;
|
||||
int lastIndex = -1, lastEndIndex = -1;
|
||||
@ -238,7 +238,7 @@ static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourL
|
||||
return NULL;
|
||||
}
|
||||
*topLeft = bestXY;
|
||||
result = topStart->findTop(index, endIndex, unsortable);
|
||||
result = topStart->findTop(index, endIndex, unsortable, firstPass);
|
||||
if (!result) {
|
||||
if (lastTopStart == topStart && lastIndex == *index && lastEndIndex == *endIndex) {
|
||||
*done = true;
|
||||
@ -249,9 +249,11 @@ static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourL
|
||||
lastEndIndex = *endIndex;
|
||||
}
|
||||
} while (!result);
|
||||
#if 0
|
||||
if (result) {
|
||||
*unsortable = false;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -283,18 +285,20 @@ static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
|
||||
if (contour->done()) {
|
||||
continue;
|
||||
}
|
||||
*current = contour->nonVerticalSegment(index, endIndex);
|
||||
if (*current) {
|
||||
SkOpSegment* nonVertical = contour->nonVerticalSegment(index, endIndex);
|
||||
if (nonVertical) {
|
||||
*current = nonVertical;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
||||
SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr,
|
||||
int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done) {
|
||||
int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool firstPass) {
|
||||
SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
|
||||
done, true);
|
||||
done, firstPass);
|
||||
if (!current) {
|
||||
return NULL;
|
||||
}
|
||||
@ -332,7 +336,7 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
||||
// if only remaining candidates are vertical, then they can be marked done
|
||||
SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
|
||||
skipVertical(contourList, ¤t, indexPtr, endIndexPtr);
|
||||
|
||||
SkASSERT(current); // FIXME: if null, all remaining are vertical
|
||||
SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
|
||||
tryAgain = false;
|
||||
contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit,
|
||||
@ -348,6 +352,9 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
||||
} while (tryAgain);
|
||||
current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding,
|
||||
hitOppDx);
|
||||
if (current->done()) {
|
||||
return NULL;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ void Assemble(const SkPathWriter& path, SkPathWriter* simple);
|
||||
SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex);
|
||||
SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& , SkOpAngle::IncludeType ,
|
||||
bool* firstContour, int* index, int* endIndex, SkPoint* topLeft,
|
||||
bool* unsortable, bool* done);
|
||||
bool* unsortable, bool* done, bool firstPass);
|
||||
SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end);
|
||||
void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list,
|
||||
bool evenOdd, bool oppEvenOdd);
|
||||
|
@ -94,6 +94,11 @@ bool SkDCubic::monotonicInY() const {
|
||||
}
|
||||
|
||||
bool SkDCubic::serpentine() const {
|
||||
#if 0 // FIXME: enabling this fixes cubicOp114 but breaks cubicOp58d and cubicOp53d
|
||||
double tValues[2];
|
||||
// OPTIMIZATION : another case where caching the present of cubic inflections would be useful
|
||||
return findInflections(tValues) > 1;
|
||||
#endif
|
||||
if (!controlsContainedByEnds()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -10,12 +10,12 @@
|
||||
|
||||
#if defined SK_DEBUG || !FORCE_RELEASE
|
||||
|
||||
int SkPathOpsDebug::gMaxWindSum = SK_MaxS32;
|
||||
int SkPathOpsDebug::gMaxWindValue = SK_MaxS32;
|
||||
|
||||
const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"};
|
||||
|
||||
#if defined(SK_DEBUG) || !FORCE_RELEASE
|
||||
int SkPathOpsDebug::gContourID;
|
||||
int SkPathOpsDebug::gSegmentID;
|
||||
#endif
|
||||
|
||||
#if DEBUG_SORT || DEBUG_SWAP_TOP
|
||||
int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
|
||||
@ -393,6 +393,17 @@ bool SkOpSegment::debugContains(const SkOpAngle* angle) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG_SWAP_TOP
|
||||
int SkOpSegment::debugInflections(int tStart, int tEnd) const {
|
||||
if (fVerb != SkPath::kCubic_Verb) {
|
||||
return false;
|
||||
}
|
||||
SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
|
||||
double inflections[2];
|
||||
return dst.findInflections(inflections);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkOpSegment::debugReset() {
|
||||
fTs.reset();
|
||||
fAngles.reset();
|
||||
|
@ -52,6 +52,7 @@
|
||||
#define DEBUG_CROSS 0
|
||||
#define DEBUG_FLAT_QUADS 0
|
||||
#define DEBUG_FLOW 0
|
||||
#define DEBUG_LIMIT_WIND_SUM 0
|
||||
#define DEBUG_MARK_DONE 0
|
||||
#define DEBUG_PATH_CONSTRUCTION 0
|
||||
#define DEBUG_SHOW_TEST_NAME 0
|
||||
@ -85,6 +86,7 @@
|
||||
#define DEBUG_CROSS 01
|
||||
#define DEBUG_FLAT_QUADS 0
|
||||
#define DEBUG_FLOW 1
|
||||
#define DEBUG_LIMIT_WIND_SUM 4
|
||||
#define DEBUG_MARK_DONE 1
|
||||
#define DEBUG_PATH_CONSTRUCTION 1
|
||||
#define DEBUG_SHOW_TEST_NAME 1
|
||||
@ -96,7 +98,7 @@
|
||||
#define DEBUG_SORT_SINGLE 0
|
||||
#define DEBUG_SWAP_TOP 1
|
||||
#define DEBUG_UNSORTABLE 1
|
||||
#define DEBUG_VALIDATE 1
|
||||
#define DEBUG_VALIDATE 0
|
||||
#define DEBUG_WIND_BUMP 0
|
||||
#define DEBUG_WINDING 1
|
||||
#define DEBUG_WINDING_AT_T 1
|
||||
@ -134,12 +136,12 @@
|
||||
|
||||
class SkPathOpsDebug {
|
||||
public:
|
||||
static int gMaxWindSum;
|
||||
static int gMaxWindValue;
|
||||
|
||||
static const char* kLVerbStr[];
|
||||
|
||||
#if defined(SK_DEBUG) || !FORCE_RELEASE
|
||||
static int gContourID;
|
||||
static int gSegmentID;
|
||||
#endif
|
||||
|
||||
#if DEBUG_SORT || DEBUG_SWAP_TOP
|
||||
static int gSortCountDefault;
|
||||
|
@ -21,6 +21,9 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e
|
||||
*endIndex = -1;
|
||||
if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endIndex, &done,
|
||||
&sortable)) {
|
||||
if (last->unorderable()) {
|
||||
continue;
|
||||
}
|
||||
*tIndex = last->start();
|
||||
*endIndex = last->end();
|
||||
#if TRY_ROTATE
|
||||
@ -116,21 +119,31 @@ static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp o
|
||||
bool firstContour = true;
|
||||
bool unsortable = false;
|
||||
bool topUnsortable = false;
|
||||
bool firstPass = true;
|
||||
SkPoint lastTopLeft;
|
||||
SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
|
||||
do {
|
||||
int index, endIndex;
|
||||
bool done;
|
||||
bool topDone;
|
||||
lastTopLeft = topLeft;
|
||||
SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kBinarySingle, &firstContour,
|
||||
&index, &endIndex, &topLeft, &topUnsortable, &done);
|
||||
&index, &endIndex, &topLeft, &topUnsortable, &topDone, firstPass);
|
||||
if (!current) {
|
||||
if (topUnsortable || !done) {
|
||||
topUnsortable = false;
|
||||
if ((!topUnsortable || firstPass) && !topDone) {
|
||||
SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
|
||||
if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_ScalarMin) {
|
||||
if (firstPass) {
|
||||
firstPass = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
topLeft.fX = topLeft.fY = SK_ScalarMin;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
firstPass = !topUnsortable || lastTopLeft != topLeft;
|
||||
SkTDArray<SkOpSpan*> chaseArray;
|
||||
do {
|
||||
if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) {
|
||||
|
@ -13,21 +13,24 @@ static bool bridgeWinding(SkTArray<SkOpContour*, true>& contourList, SkPathWrite
|
||||
bool firstContour = true;
|
||||
bool unsortable = false;
|
||||
bool topUnsortable = false;
|
||||
bool firstPass = true;
|
||||
SkPoint lastTopLeft;
|
||||
SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
|
||||
do {
|
||||
int index, endIndex;
|
||||
bool topDone;
|
||||
lastTopLeft = topLeft;
|
||||
SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kUnaryWinding, &firstContour,
|
||||
&index, &endIndex, &topLeft, &topUnsortable, &topDone);
|
||||
&index, &endIndex, &topLeft, &topUnsortable, &topDone, firstPass);
|
||||
if (!current) {
|
||||
if (topUnsortable || !topDone) {
|
||||
topUnsortable = false;
|
||||
if ((!topUnsortable || firstPass) && !topDone) {
|
||||
SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
|
||||
topLeft.fX = topLeft.fY = SK_ScalarMin;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
firstPass = !topUnsortable || lastTopLeft != topLeft;
|
||||
SkTDArray<SkOpSpan*> chaseArray;
|
||||
do {
|
||||
if (current->activeWinding(index, endIndex)) {
|
||||
|
@ -161,8 +161,8 @@ static int check_linear(const SkDCubic& cubic,
|
||||
while (cubic[startIndex].approximatelyEqual(cubic[endIndex])) {
|
||||
--endIndex;
|
||||
if (endIndex == 0) {
|
||||
SkDebugf("%s shouldn't get here if all four points are about equal\n", __FUNCTION__);
|
||||
SkASSERT(0);
|
||||
endIndex = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cubic.isLinear(startIndex, endIndex)) {
|
||||
|
@ -202,6 +202,10 @@ void SkIntersectionHelper::dump() const {
|
||||
}
|
||||
}
|
||||
|
||||
const SkTDArray<SkOpSpan>& SkOpSegment::debugSpans() const {
|
||||
return fTs;
|
||||
}
|
||||
|
||||
void SkOpSegment::dumpAngles() const {
|
||||
SkDebugf("((SkOpSegment*) 0x%p) [%d]\n", this, debugID());
|
||||
int fromIndex = -1, toIndex = -1;
|
||||
@ -371,8 +375,8 @@ const SkOpSegment* SkOpSpan::debugToSegment(ptrdiff_t* spanIndex) const {
|
||||
}
|
||||
SkASSERT(otherTestT == fOtherT);
|
||||
const SkOpSegment* candidate = otherSpan.fOther;
|
||||
const SkOpSpan* first = candidate->spans().begin();
|
||||
const SkOpSpan* last = candidate->spans().end() - 1;
|
||||
const SkOpSpan* first = candidate->debugSpans().begin();
|
||||
const SkOpSpan* last = candidate->debugSpans().end() - 1;
|
||||
if (first <= this && this <= last) {
|
||||
if (spanIndex) {
|
||||
*spanIndex = this - first;
|
||||
@ -415,12 +419,6 @@ void SkOpSpan::dumpOne() const {
|
||||
if (fDone) {
|
||||
SkDebugf(" done");
|
||||
}
|
||||
if (fUnsortableStart) {
|
||||
SkDebugf(" unsortable-start");
|
||||
}
|
||||
if (fUnsortableEnd) {
|
||||
SkDebugf(" unsortable-end");
|
||||
}
|
||||
if (fTiny) {
|
||||
SkDebugf(" tiny");
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkForceLinking.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkRTConf.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkThread.h"
|
||||
@ -566,8 +566,12 @@ bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char*
|
||||
}
|
||||
|
||||
#if DEBUG_SHOW_TEST_NAME
|
||||
|
||||
SK_DECLARE_STATIC_MUTEX(gTestMutex);
|
||||
|
||||
void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
|
||||
const char* testName) {
|
||||
SkAutoMutexAcquire ac(gTestMutex);
|
||||
ShowFunctionHeader(testName);
|
||||
showPath(a, "path", true);
|
||||
showPath(b, "pathB", true);
|
||||
@ -661,10 +665,6 @@ int initializeTests(skiatest::Reporter* reporter, const char* test) {
|
||||
#if 0 // doesn't work yet
|
||||
SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
|
||||
SK_CONF_SET("images.png.suppressDecoderWarnings", true);
|
||||
#endif
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = 4;
|
||||
SkPathOpsDebug::gMaxWindValue = 4;
|
||||
#endif
|
||||
if (reporter->verbose()) {
|
||||
SkAutoMutexAcquire lock(gMutex);
|
||||
|
103
tests/PathOpsOpLoopThreadedTest.cpp
Executable file
103
tests/PathOpsOpLoopThreadedTest.cpp
Executable file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "PathOpsExtendedTest.h"
|
||||
#include "PathOpsThreadedCommon.h"
|
||||
|
||||
static void testOpLoopsMain(PathOpsThreadState* data) {
|
||||
#if DEBUG_SHOW_TEST_NAME
|
||||
strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
|
||||
#endif
|
||||
SkASSERT(data);
|
||||
PathOpsThreadState& state = *data;
|
||||
char pathStr[1024]; // gdb: set print elements 400
|
||||
bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
|
||||
if (progress) {
|
||||
sk_bzero(pathStr, sizeof(pathStr));
|
||||
}
|
||||
for (int a = 0 ; a < 6; ++a) {
|
||||
for (int b = a + 1 ; b < 7; ++b) {
|
||||
for (int c = 0 ; c < 6; ++c) {
|
||||
for (int d = c + 1 ; d < 7; ++d) {
|
||||
// define 4 points that form two lines that often cross; one line is (a, b) (c, d)
|
||||
SkVector v = {SkIntToScalar(a - c), SkIntToScalar(b - d)};
|
||||
SkPoint midA = { SkIntToScalar(a * state.fA + c * (6 - state.fA)) / 6,
|
||||
SkIntToScalar(b * state.fA + d * (6 - state.fA)) / 6 };
|
||||
SkPoint midB = { SkIntToScalar(a * state.fB + c * (6 - state.fB)) / 6,
|
||||
SkIntToScalar(b * state.fB + d * (6 - state.fB)) / 6 };
|
||||
SkPoint endC = { midA.fX + v.fY * state.fC / 3,
|
||||
midA.fY + v.fX * state.fC / 3 };
|
||||
SkPoint endD = { midB.fX - v.fY * state.fD / 3,
|
||||
midB.fY + v.fX * state.fD / 3 };
|
||||
SkPath pathA, pathB;
|
||||
if (progress) {
|
||||
char* str = pathStr;
|
||||
str += sprintf(str, " path.moveTo(%d,%d);\n", a, b);
|
||||
str += sprintf(str, " path.cubicTo(%d,%d, %1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
|
||||
c, d, endC.fX, endC.fY, endD.fX, endD.fY);
|
||||
str += sprintf(str, " path.close();\n");
|
||||
str += sprintf(str, " pathB.moveTo(%d,%d);\n", c, d);
|
||||
str += sprintf(str, " pathB.cubicTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf, %d,%d);\n",
|
||||
endC.fX, endC.fY, endD.fX, endD.fY, a, b);
|
||||
str += sprintf(str, " pathB.close();\n");
|
||||
}
|
||||
pathA.moveTo(SkIntToScalar(a), SkIntToScalar(b));
|
||||
pathA.cubicTo(SkIntToScalar(c), SkIntToScalar(d), endC.fX, endC.fY, endD.fX, endD.fY);
|
||||
pathA.close();
|
||||
pathB.moveTo(SkIntToScalar(c), SkIntToScalar(d));
|
||||
pathB.cubicTo(endC.fX, endC.fY, endD.fX, endD.fY, SkIntToScalar(a), SkIntToScalar(b));
|
||||
pathB.close();
|
||||
// SkDebugf("%s\n", pathStr);
|
||||
if (progress) {
|
||||
outputProgress(state.fPathStr, pathStr, kIntersect_PathOp);
|
||||
}
|
||||
testThreadedPathOp(state.fReporter, pathA, pathB, kIntersect_PathOp, "loops");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(PathOpsOpLoopsThreaded, reporter) {
|
||||
int threadCount = initializeTests(reporter, "cubicOp");
|
||||
PathOpsThreadedTestRunner testRunner(reporter, threadCount);
|
||||
for (int a = 0; a < 6; ++a) { // outermost
|
||||
for (int b = a + 1; b < 7; ++b) {
|
||||
for (int c = 0 ; c < 6; ++c) {
|
||||
for (int d = c + 1; d < 7; ++d) {
|
||||
*testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
|
||||
(&testOpLoopsMain, a, b, c, d, &testRunner));
|
||||
}
|
||||
}
|
||||
if (!reporter->allowExtendedTest()) goto finish;
|
||||
}
|
||||
}
|
||||
finish:
|
||||
testRunner.render();
|
||||
ShowTestArray();
|
||||
}
|
||||
|
||||
DEF_TEST(PathOpsOpLoops, reporter) {
|
||||
(void) initializeTests(reporter, "cubicOp");
|
||||
PathOpsThreadState state;
|
||||
state.fReporter = reporter;
|
||||
SkBitmap bitmap;
|
||||
state.fBitmap = &bitmap;
|
||||
char pathStr[PATH_STR_SIZE];
|
||||
state.fPathStr = pathStr;
|
||||
for (state.fA = 0; state.fA < 6; ++state.fA) { // outermost
|
||||
for (state.fB = state.fA + 1; state.fB < 7; ++state.fB) {
|
||||
for (state.fC = 0 ; state.fC < 6; ++state.fC) {
|
||||
for (state.fD = state.fC + 1; state.fD < 7; ++state.fD) {
|
||||
testOpLoopsMain(&state);
|
||||
}
|
||||
}
|
||||
if (!reporter->allowExtendedTest()) goto finish;
|
||||
}
|
||||
}
|
||||
finish:
|
||||
ShowTestArray();
|
||||
}
|
@ -3257,10 +3257,70 @@ static void findFirst1(skiatest::Reporter* reporter, const char* filename) {
|
||||
testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
|
||||
}
|
||||
|
||||
// triggers addSimpleAngle with non-zero argument
|
||||
static void cubicOp112(skiatest::Reporter* reporter, const char* filename) {
|
||||
SkPath path, pathB;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(2,4);
|
||||
path.cubicTo(2,3, 6,4, 1,0);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(4,6);
|
||||
pathB.cubicTo(0,1, 4,2, 3,2);
|
||||
pathB.close();
|
||||
testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
|
||||
}
|
||||
|
||||
// triggers untested calcLoopSpanCount code path
|
||||
#if 0
|
||||
static void cubicOp113(skiatest::Reporter* reporter, const char* filename) {
|
||||
SkPath path, pathB;
|
||||
path.moveTo(2,4);
|
||||
path.cubicTo(3,5, 2.33333325f,4.33333349f, 3.83333325f,3.83333349f);
|
||||
path.close();
|
||||
pathB.moveTo(3,5);
|
||||
pathB.cubicTo(2.33333325f,4.33333349f, 3.83333325f,3.83333349f, 2,4);
|
||||
pathB.close();
|
||||
testPathOp(reporter, path, pathB, kDifference_PathOp, filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cubicOp114(skiatest::Reporter* reporter, const char* filename) {
|
||||
SkPath path, pathB;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0, 1);
|
||||
path.cubicTo(1, 3, -1, 2, 3.5f, 1.33333337f);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(1, 3);
|
||||
pathB.cubicTo(-1, 2, 3.5f, 1.33333337f, 0, 1);
|
||||
pathB.close();
|
||||
testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
|
||||
}
|
||||
|
||||
static void quadOp10i(skiatest::Reporter* reporter, const char* filename) {
|
||||
SkPath path, pathB;
|
||||
path.moveTo(0, 0);
|
||||
path.quadTo(1, 8, 3, 5);
|
||||
path.lineTo(8, 1);
|
||||
path.close();
|
||||
pathB.moveTo(0, 0);
|
||||
pathB.quadTo(8, 1, 4, 8);
|
||||
pathB.close();
|
||||
testPathOp(reporter, path, pathB, kIntersect_PathOp, filename);
|
||||
}
|
||||
|
||||
static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
|
||||
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
|
||||
|
||||
static struct TestDesc tests[] = {
|
||||
TEST(quadOp10i),
|
||||
#if 0 // FIXME: serpentine curve is ordered the wrong way
|
||||
TEST(cubicOp114),
|
||||
#endif
|
||||
#if 0 // FIXME: currently failing
|
||||
TEST(cubicOp113),
|
||||
#endif
|
||||
#if SKPS_WORKING
|
||||
// fails because a cubic/quadratic intersection is missed
|
||||
// the internal quad/quad is far enough away from the real cubic/quad that it is rejected
|
||||
@ -3269,6 +3329,7 @@ static struct TestDesc tests[] = {
|
||||
#if ISSUE_1417_WORKING_ON_LINUX_32
|
||||
TEST(issue1417),
|
||||
#endif
|
||||
TEST(cubicOp112),
|
||||
TEST(skpadspert_net23),
|
||||
TEST(skpadspert_de11),
|
||||
TEST(findFirst1),
|
||||
@ -3467,11 +3528,9 @@ static struct TestDesc tests[] = {
|
||||
static const size_t testCount = SK_ARRAY_COUNT(tests);
|
||||
|
||||
static struct TestDesc subTests[] = {
|
||||
TEST(cubicOp6d),
|
||||
TEST(cubicOp8d),
|
||||
TEST(cubicOp70d),
|
||||
TEST(cubicOp16d),
|
||||
TEST(skp5),
|
||||
TEST(cubicOp114),
|
||||
TEST(cubicOp58d),
|
||||
TEST(cubicOp53d),
|
||||
};
|
||||
|
||||
static const size_t subTestCount = SK_ARRAY_COUNT(subTests);
|
||||
@ -3483,10 +3542,6 @@ static bool runSubTestsFirst = false;
|
||||
static bool runReverse = false;
|
||||
|
||||
DEF_TEST(PathOpsOp, reporter) {
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = 4;
|
||||
SkPathOpsDebug::gMaxWindValue = 4;
|
||||
#endif
|
||||
#if DEBUG_SHOW_TEST_NAME
|
||||
strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
|
||||
#endif
|
||||
@ -3497,10 +3552,6 @@ DEF_TEST(PathOpsOp, reporter) {
|
||||
if (runSubTests && !runSubTestsFirst) {
|
||||
RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = SK_MaxS32;
|
||||
SkPathOpsDebug::gMaxWindValue = SK_MaxS32;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void bufferOverflow(skiatest::Reporter* reporter, const char* filename) {
|
||||
@ -3518,10 +3569,6 @@ static struct TestDesc failTests[] = {
|
||||
static const size_t failTestCount = SK_ARRAY_COUNT(failTests);
|
||||
|
||||
DEF_TEST(PathOpsFailOp, reporter) {
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = 4;
|
||||
SkPathOpsDebug::gMaxWindValue = 4;
|
||||
#endif
|
||||
#if DEBUG_SHOW_TEST_NAME
|
||||
strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
|
||||
#endif
|
||||
|
@ -5086,10 +5086,6 @@ static bool runReverse = false;
|
||||
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
|
||||
|
||||
DEF_TEST(PathOpsSimplify, reporter) {
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = 4;
|
||||
SkPathOpsDebug::gMaxWindValue = 4;
|
||||
#endif
|
||||
if (runSubTests && runSubTestsFirst) {
|
||||
RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
|
||||
}
|
||||
@ -5097,8 +5093,4 @@ DEF_TEST(PathOpsSimplify, reporter) {
|
||||
if (runSubTests && !runSubTestsFirst) {
|
||||
RunTestSet(reporter, subTests, subTestCount, firstSubTest, stopTest, runReverse);
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = SK_MaxS32;
|
||||
SkPathOpsDebug::gMaxWindValue = SK_MaxS32;
|
||||
#endif
|
||||
}
|
||||
|
@ -26,22 +26,86 @@
|
||||
#define OUT_DIR "D:\\skpOut\\1\\"
|
||||
#else
|
||||
#define PATH_SLASH "/"
|
||||
#define IN_DIR "/skp/slave"
|
||||
#define OUT_DIR "/skpOut/1/"
|
||||
#define IN_DIR "/skp/2311328-7fc2228/slave"
|
||||
#define OUT_DIR "/skpOut/2/"
|
||||
#endif
|
||||
|
||||
const struct {
|
||||
int directory;
|
||||
const char* filename;
|
||||
} skipOverSept[] = {
|
||||
{1, "http___elpais_com_.skp"},
|
||||
{1, "http___namecheap_com_.skp"},
|
||||
{1, "http___www_alrakoba_net_.skp"},
|
||||
{1, "http___www_briian_com_.skp"}, // triggers assert at line 467 of SkRRect.cpp
|
||||
{1, "http___www_cityads_ru_.skp"},
|
||||
{3, "http___www_abeautifulmess_com_.skp"}, // asserts in IntToFixed from SkScan::AntiFilllXRect
|
||||
{1, "http___www_dealnews_com_.skp"},
|
||||
{1, "http___www_inmotionhosting_com.skp"},
|
||||
{ 9, "http___www_catingueiraonline_com_.skp"}, // infinite loop
|
||||
{13, "http___www_galaxystwo_com_.skp"}, // infinite loop
|
||||
{15, "http___www_giffingtool_com_.skp"}, // joinCoincidence / findT / assert
|
||||
{15, "http___www_thaienews_blogspot_com_.skp"}, // infinite loop
|
||||
{17, "http___www_gruposejaumdivulgador_com_br_.skp"}, // calcCoincidentWinding asserts zeroSpan
|
||||
{18, "http___www_argus_presse_fr_.skp"}, // can't find winding of remaining vertical edge
|
||||
{21, "http___www_fashionscandal_com_.skp"}, // infinite loop
|
||||
{21, "http___www_kenlevine_blogspot_com_.skp"}, // infinite loop
|
||||
{25, "http___www_defense_studies_blogspot_com_.skp"}, // infinite loop
|
||||
{27, "http___www_brokeroutpost_com_.skp"}, // suspect infinite loop
|
||||
{28, "http___www_jaimebatistadasilva_blogspot_com_br_.skp"}, // suspect infinite loop
|
||||
{28, "http___www_odia_com_br_.skp"}, // !simple->isClosed()
|
||||
{29, "http___www_hubbyscook_com_.skp"}, // joinCoincidence / findT / assert
|
||||
{30, "http___www_spankystokes_com_.skp"}, // suspect infinite loop
|
||||
{32, "http___www_adalbertoday_blogspot_com_br_.skp"}, // suspect infinite loop
|
||||
{32, "http___www_galery_annisa_com_.skp"}, // suspect infinite loop
|
||||
{33, "http___www_pindosiya_com_.skp"}, // line quad intersection SkIntersections::assert
|
||||
{36, "http___www_educationalcraft_com_.skp"}, // cubic / cubic near end / assert in SkIntersections::insert (missing skp test)
|
||||
{36, "http___www_shaam_org_.skp"}, // suspect infinite loop
|
||||
{36, "http___www_my_pillow_book_blogspot_gr_.skp"}, // suspect infinite loop
|
||||
{39, "http___www_opbeat_com_.skp"}, // suspect infinite loop
|
||||
{40, "http___www_phototransferapp_com_.skp"}, // !simple->isClosed()
|
||||
{41, "http___www_freeismylife_com_.skp"}, // suspect infinite loop
|
||||
{41, "http___www_accordidelmomento_com_.skp"}, // suspect infinite loop
|
||||
{41, "http___www_evolvehq_com_.skp"}, // joinCoincidence / findT / assert
|
||||
{44, "http___www_contextualnewsfeeds_com_.skp"}, // !simple->isClosed()
|
||||
{44, "http___www_cooksnaps_com_.skp"}, // !simple->isClosed()
|
||||
{44, "http___www_helha_be_.skp"}, // !simple->isClosed()
|
||||
{45, "http___www_blondesmakemoney_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{46, "http___www_cheaphealthygood_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{47, "http___www_ajitvadakayil_blogspot_in_.skp"}, // suspect infinite loop
|
||||
{49, "http___www_karnivool_com_au_.skp"}, // SkOpAngle::setSector SkASSERT(fSectorStart >= 0);
|
||||
{49, "http___www_tunero_de_.skp"}, // computeonesumreverse calls markwinding with 0 winding
|
||||
{49, "http___www_thaienews_blogspot_sg_.skp"}, // suspect infinite loop
|
||||
{50, "http___www_docgelo_com_.skp"}, // rightAngleWinding (probably same as argus_presse)
|
||||
{53, "http___www_lojaanabotafogo_com_br_.skp"}, // rrect validate assert
|
||||
{54, "http___www_odecktestanswer2013_blogspot_in_.skp"}, // suspect infinite loop
|
||||
{54, "http___www_cleristonsilva_com_br_.skp"}, // suspect infinite loop
|
||||
{56, "http___www_simplysaru_com_.skp"}, // joinCoincidence / findT / assert
|
||||
{57, "http___www_koukfamily_blogspot_gr_.skp"}, // suspect infinite loop
|
||||
{57, "http___www_dinar2010_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{58, "http___www_artblart_com_.skp"}, // rightAngleWinding
|
||||
{59, "http___www_accrispin_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{59, "http___www_vicisitudysordidez_blogspot_com_es_.skp"}, // suspect infinite loop
|
||||
{60, "http___www_thehousingbubbleblog_com_.skp"}, // suspect infinite loop
|
||||
{61, "http___www_jessicaslens_wordpress_com_.skp"}, // joinCoincidence / findT / assert
|
||||
{61, "http___www_partsdata_de_.skp"}, // cubic-cubic intersection reduce checkLinear assert
|
||||
{62, "http___www_blondesmakemoney_blogspot_com_au_.skp"}, // suspect infinite loop
|
||||
{62, "http___www_intellibriefs_blogspot_in_.skp"}, // suspect infinite loop
|
||||
{63, "http___www_tankerenemy_com_.skp"}, // suspect infinite loop
|
||||
{65, "http___www_kpopexplorer_net_.skp"}, // joinCoincidence / findT / assert
|
||||
{65, "http___www_bestthingsinbeauty_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{65, "http___www_wartepop_blogspot_com_br_.skp"}, // !simple->isClosed()
|
||||
{65, "http___www_eolake_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{67, "http___www_cacadordemisterio_blogspot_com_br_.skp"}, // suspect infinite loop
|
||||
{69, "http___www_misnotasyapuntes_blogspot_mx_.skp"}, // suspect infinite loop
|
||||
{69, "http___www_awalkintheparknyc_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{71, "http___www_lokado_de_.skp"}, // joinCoincidence / findT / assert
|
||||
{72, "http___www_karlosdesanjuan_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{73, "http___www_cyberlawsinindia_blogspot_in_.skp"}, // suspect infinite loop
|
||||
{73, "http___www_taxiemmovimento_blogspot_com_br_.skp"}, // suspect infinite loop
|
||||
{74, "http___www_giveusliberty1776_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{75, "http___www_e_cynical_blogspot_gr_.skp"}, // suspect infinite loop
|
||||
{76, "http___www_seopack_blogspot_com_.skp"}, // SkOpAngle::setSector SkASSERT(fSectorStart >= 0);
|
||||
{77, "http___www_sunsky_russia_com_.skp"}, // joinCoincidence / findT / assert (no op test, already fixed hopefully)
|
||||
{78, "http___www_bisnisonlineinfo_com_.skp"}, // suspect infinite loop
|
||||
{79, "http___www_danielsgroupcpa_com_.skp"}, // joinCoincidence / findT / assert (no op test, already fixed hopefully)
|
||||
{80, "http___www_clinique_portugal_com_.skp"}, // suspect infinite loop
|
||||
{81, "http___www_europebusines_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{82, "http___www_apopsignomi_blogspot_gr_.skp"}, // suspect infinite loop
|
||||
{85, "http___www_ajitvadakayil_blogspot_com_.skp"}, // suspect infinite loop
|
||||
{86, "http___www_madhousefamilyreviews_blogspot_co_uk_.skp"}, // suspect infinite loop
|
||||
};
|
||||
|
||||
size_t skipOverSeptCount = sizeof(skipOverSept) / sizeof(skipOverSept[0]);
|
||||
@ -409,6 +473,9 @@ void TestResult::testOne() {
|
||||
int height = pic->height();
|
||||
SkBitmap oldBitmap, opBitmap;
|
||||
fScale = 1;
|
||||
while (width / fScale > 32767 || height / fScale > 32767) {
|
||||
++fScale;
|
||||
}
|
||||
do {
|
||||
int dimX = (width + fScale - 1) / fScale;
|
||||
int dimY = (height + fScale - 1) / fScale;
|
||||
@ -417,7 +484,7 @@ void TestResult::testOne() {
|
||||
break;
|
||||
}
|
||||
SkDebugf("-%d-", fScale);
|
||||
} while ((fScale *= 2) < 256);
|
||||
} while (++fScale < 256);
|
||||
if (fScale >= 256) {
|
||||
SkDebugf("unable to allocate bitmap for %s (w=%d h=%d)\n", fFilename,
|
||||
width, height);
|
||||
@ -458,9 +525,10 @@ static SkString makeStatusString(int dirNo) {
|
||||
|
||||
class PreParser {
|
||||
public:
|
||||
PreParser(int dirNo)
|
||||
PreParser(int dirNo, bool threaded)
|
||||
: fDirNo(dirNo)
|
||||
, fIndex(0) {
|
||||
, fIndex(0)
|
||||
, fThreaded(threaded) {
|
||||
SkString statusPath = makeStatusString(dirNo);
|
||||
if (!sk_exists(statusPath.c_str())) {
|
||||
return;
|
||||
@ -481,7 +549,7 @@ public:
|
||||
do {
|
||||
bool readOne = reader.read(&c, 1) != 0;
|
||||
if (!readOne) {
|
||||
SkASSERT(i == 0);
|
||||
// SkASSERT(i == 0); // the current text may be incomplete -- if so, ignore it
|
||||
return false;
|
||||
}
|
||||
if (c == ' ') {
|
||||
@ -492,7 +560,9 @@ public:
|
||||
SkASSERT(i < kMaxLength);
|
||||
} while (true);
|
||||
do {
|
||||
SkAssertResult(reader.read(&c, 1));
|
||||
if (!reader.read(&c, 1)) {
|
||||
return false;
|
||||
}
|
||||
if (c == ' ') {
|
||||
break;
|
||||
}
|
||||
@ -501,7 +571,9 @@ public:
|
||||
} while (true);
|
||||
bool minus = false;
|
||||
do {
|
||||
SkAssertResult(reader.read(&c, 1));
|
||||
if (!reader.read(&c, 1)) {
|
||||
return false;
|
||||
}
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
@ -519,7 +591,17 @@ public:
|
||||
}
|
||||
|
||||
bool match(const SkString& filename, SkFILEWStream* stream, TestResult* result) {
|
||||
if (fIndex < fResults.count()) {
|
||||
if (fThreaded) {
|
||||
for (int index = 0; index < fResults.count(); ++index) {
|
||||
const TestResult& test = fResults[index];
|
||||
if (filename.equals(test.fFilename)) {
|
||||
*result = test;
|
||||
SkString outStr(result->status());
|
||||
stream->write(outStr.c_str(), outStr.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (fIndex < fResults.count()) {
|
||||
*result = fResults[fIndex++];
|
||||
SkASSERT(filename.equals(result->fFilename));
|
||||
SkString outStr(result->status());
|
||||
@ -533,9 +615,10 @@ private:
|
||||
int fDirNo;
|
||||
int fIndex;
|
||||
SkTArray<TestResult, true> fResults;
|
||||
bool fThreaded;
|
||||
};
|
||||
|
||||
static bool doOneDir(TestState* state) {
|
||||
static bool doOneDir(TestState* state, bool threaded) {
|
||||
int dirNo = state->fResult.fDirNo;
|
||||
skiatest::Reporter* reporter = state->fReporter;
|
||||
SkString dirName = make_in_dir_name(dirNo);
|
||||
@ -545,7 +628,7 @@ static bool doOneDir(TestState* state) {
|
||||
SkOSFile::Iter iter(dirName.c_str(), "skp");
|
||||
SkString filename;
|
||||
int testCount = 0;
|
||||
PreParser preParser(dirNo);
|
||||
PreParser preParser(dirNo, threaded);
|
||||
SkFILEWStream statusStream(makeStatusString(dirNo).c_str());
|
||||
while (iter.next(&filename)) {
|
||||
for (size_t index = 0; index < skipOverSeptCount; ++index) {
|
||||
@ -632,7 +715,7 @@ DEF_TEST(PathOpsSkpClip, reporter) {
|
||||
SkDebugf("dirNo=%d\n", dirNo);
|
||||
}
|
||||
state.fResult.fDirNo = dirNo;
|
||||
if (!doOneDir(&state)) {
|
||||
if (!doOneDir(&state, false)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -640,7 +723,7 @@ DEF_TEST(PathOpsSkpClip, reporter) {
|
||||
}
|
||||
|
||||
static void testSkpClipMain(TestState* data) {
|
||||
(void) doOneDir(data);
|
||||
(void) doOneDir(data, true);
|
||||
}
|
||||
|
||||
DEF_TEST(PathOpsSkpClipThreaded, reporter) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,8 +20,4 @@ void PathOpsThreadedTestRunner::render() {
|
||||
for (int index = 0; index < fRunnables.count(); ++ index) {
|
||||
pool.add(fRunnables[index]);
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gMaxWindSum = SK_MaxS32;
|
||||
SkPathOpsDebug::gMaxWindValue = SK_MaxS32;
|
||||
#endif
|
||||
}
|
||||
|
@ -826,11 +826,60 @@ op intersect
|
||||
{{{1000, 13}, {999.969971f, 37.0299988f}}}
|
||||
</div>
|
||||
|
||||
<div id="skpwww_maturesupertube_com_21">
|
||||
{{{{3.87867975f, 11831.8789f}, {4.7573595f, 11831}, {6, 11831}}},
|
||||
{{{2, 11830}, {4.5f, 11832.5f}}}},
|
||||
</div>
|
||||
|
||||
<div id="loop1">
|
||||
{{1, 4, 2, 6, 0, 5, 4.5f, 4.33333302f
|
||||
{{2, 6, 0, 5, 4.5f, 4.33333302f, 1, 4
|
||||
{{{3, 5}, {2.33333325f, 4.33333349f}, {3.83333325f, 3.83333349f}, {2, 4}}}
|
||||
{{{2, 4}, {3, 5}, {2.33333325f, 4.33333349f}, {3.83333325f, 3.83333349f}}}
|
||||
</div>
|
||||
|
||||
<div id="serp1">
|
||||
{{{0.55431359440952721, 2.1086271888190544}, {0.1588954256872922, 2.3078315988141811}, {0.57446808656344528, 2.1489361731268914}, {0, 1}}}
|
||||
{{{0.55431359440952721, 2.1086271888190544}, {0.1588954256872922, 2.3078315988141811}, {0.57446808656344528, 2.1489361731268914}, {0, 1}}}
|
||||
</div>
|
||||
<div id="serp2">
|
||||
{{{4.0946656649135988, 3.283996994740797}, {4.1983471074380168, 2.1074380165289259}, {4.5454545454545459, 1.3636363636363635}, {4, 3}}}
|
||||
{{{4.0946656649135988, 3.283996994740797}, {4.1983471074380168, 2.1074380165289259}, {4.5454545454545459, 1.3636363636363635}, {4, 3}}}
|
||||
</div>
|
||||
<div id="serp3">
|
||||
{{{2.2015477442471254, 1.1371488033013577}, {2.3167674423028526, 0.68323255769714741}, {2.4076432497431028, 0.59235675025689716}, {2, 1}}}
|
||||
{{{2.2015477442471254, 1.1371488033013577}, {2.3167674423028526, 0.68323255769714741}, {2.4076432497431028, 0.59235675025689716}, {2, 1}}}
|
||||
</div>
|
||||
|
||||
<div id="skpwww_seopack_blogspot_com_2153">
|
||||
{{{924, 245.472672f}, {1143, 247}}}
|
||||
{{{1000, 246}, {927.340759f, 245.505722f}}}
|
||||
{{{999.892212f, 246}, {927.340759f, 245.505722f}}}
|
||||
</div>
|
||||
|
||||
<div id="self1">
|
||||
{{{2, 3}, {0, 4}, {3, 2}, {5, 3}}}
|
||||
{{{2, 3}, {0, 4}, {3, 2}, {5, 3}}}
|
||||
</div>
|
||||
|
||||
<div id="skpwww_pindosiya_com_99">
|
||||
{{{901.0869140625, 547}, {899, 556}}}
|
||||
{{{900.0235595703125, 551.60284423828125}, {900.06072998046875, 551.29705810546875}, {900.15655517578125, 551.0157470703125}}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
skpwww_pindosiya_com_99,
|
||||
self1,
|
||||
skpwww_seopack_blogspot_com_2153,
|
||||
serp1,
|
||||
serp2,
|
||||
serp3,
|
||||
loop1,
|
||||
skpwww_maturesupertube_com_21,
|
||||
skpwww_cityads_ru_249,
|
||||
skpelpais_com_18,
|
||||
testQuads60_b,
|
||||
@ -1492,7 +1541,7 @@ function dxy_at_t(curve, t) {
|
||||
for (var curves in test) {
|
||||
var curve = test[curves];
|
||||
if (curve.length == 6 || curve.length == 8) {
|
||||
var opp = curves == 1 ? 0 : 1;
|
||||
var opp = curves == 0 || curves == 1 ? 0 : 1;
|
||||
var sects = ray_curve_intersect(origin, hullEnds[opp], curve);
|
||||
intersect.push(sects);
|
||||
if (sects.length > 1) {
|
||||
@ -1515,7 +1564,7 @@ function dxy_at_t(curve, t) {
|
||||
}
|
||||
}
|
||||
}
|
||||
var midLeft = crossPt(origin, midSpokes[0], midSpokes[1]);
|
||||
var midLeft = curves != 0 ? crossPt(origin, midSpokes[0], midSpokes[1]) : 0;
|
||||
var firstInside;
|
||||
if (useIntersect) {
|
||||
var sect1 = intersect[0].length > 1;
|
||||
|
Loading…
Reference in New Issue
Block a user