path ops -- handle non-finite numbers
Op() and Simplify() do nothing if the input
is non-finite. Add code and tests.
Review URL: https://codereview.chromium.org/14407006
git-svn-id: http://skia.googlecode.com/svn/trunk@8882 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp
index d1d7af8..57e3b41 100644
--- a/src/pathops/SkOpEdgeBuilder.cpp
+++ b/src/pathops/SkOpEdgeBuilder.cpp
@@ -16,6 +16,7 @@
gContourID = 0;
gSegmentID = 0;
#endif
+ fUnparseable = false;
fSecondHalf = preFetch();
}
@@ -28,8 +29,10 @@
preFetch();
}
-void SkOpEdgeBuilder::finish() {
- walk();
+bool SkOpEdgeBuilder::finish() {
+ if (fUnparseable || !walk()) {
+ return false;
+ }
complete();
if (fCurrentContour && !fCurrentContour->segments().count()) {
fContours.pop_back();
@@ -51,6 +54,7 @@
&fReducePts[rIndex]);
}
fExtra.reset(); // we're done with this
+ return true;
}
// Note that copying the points here avoids copying the resulting path later.
@@ -59,6 +63,10 @@
// OPTIMIZATION: This copies both sets of input points every time. If the input data was read
// directly, the output path would only need to be copied if it was also one of the input paths.
int SkOpEdgeBuilder::preFetch() {
+ if (!fPath->isFinite()) {
+ fUnparseable = true;
+ return 0;
+ }
SkPath::RawIter iter(*fPath);
SkPoint pts[4];
SkPath::Verb verb;
@@ -74,14 +82,25 @@
return fPathVerbs.count() - 1;
}
-void SkOpEdgeBuilder::walk() {
+bool SkOpEdgeBuilder::close() {
+ if (fFinalCurveStart && fFinalCurveEnd && *fFinalCurveStart != *fFinalCurveEnd) {
+ *fReducePts.append() = *fFinalCurveStart;
+ *fReducePts.append() = *fFinalCurveEnd;
+ const SkPoint* lineStart = fReducePts.end() - 2;
+ *fExtra.append() = fCurrentContour->addLine(lineStart);
+ }
+ complete();
+ return true;
+}
+
+bool SkOpEdgeBuilder::walk() {
SkPath::Verb reducedVerb;
uint8_t* verbPtr = fPathVerbs.begin();
uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
const SkPoint* pointsPtr = fPathPts.begin();
- const SkPoint* finalCurveStart = NULL;
- const SkPoint* finalCurveEnd = NULL;
SkPath::Verb verb;
+ fFinalCurveStart = NULL;
+ fFinalCurveEnd = NULL;
while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) {
if (verbPtr == endOfFirstHalf) {
fOperand = true;
@@ -89,64 +108,76 @@
verbPtr++;
switch (verb) {
case SkPath::kMove_Verb:
- complete();
+ if (fCurrentContour) {
+ if (fAllowOpenContours) {
+ complete();
+ } else if (!close()) {
+ return false;
+ }
+ }
if (!fCurrentContour) {
fCurrentContour = fContours.push_back_n(1);
fCurrentContour->setOperand(fOperand);
fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathOpsMask);
*fExtra.append() = -1; // start new contour
}
- finalCurveEnd = pointsPtr++;
+ fFinalCurveEnd = pointsPtr++;
continue;
- case SkPath::kLine_Verb:
+ case SkPath::kLine_Verb: {
+ const SkPoint& lineEnd = pointsPtr[0];
+ const SkPoint& lineStart = pointsPtr[-1];
// skip degenerate points
- if (pointsPtr[-1].fX != pointsPtr[0].fX || pointsPtr[-1].fY != pointsPtr[0].fY) {
- fCurrentContour->addLine(&pointsPtr[-1]);
+ if (lineStart.fX != lineEnd.fX || lineStart.fY != lineEnd.fY) {
+ fCurrentContour->addLine(&lineStart);
}
- break;
- case SkPath::kQuad_Verb:
- reducedVerb = SkReduceOrder::Quad(&pointsPtr[-1], &fReducePts);
+ } break;
+ case SkPath::kQuad_Verb: {
+ const SkPoint* quadStart = &pointsPtr[-1];
+ reducedVerb = SkReduceOrder::Quad(quadStart, &fReducePts);
if (reducedVerb == 0) {
break; // skip degenerate points
}
if (reducedVerb == 1) {
- *fExtra.append() =
- fCurrentContour->addLine(fReducePts.end() - 2);
+ const SkPoint* lineStart = fReducePts.end() - 2;
+ *fExtra.append() = fCurrentContour->addLine(lineStart);
break;
}
- fCurrentContour->addQuad(&pointsPtr[-1]);
- break;
- case SkPath::kCubic_Verb:
- reducedVerb = SkReduceOrder::Cubic(&pointsPtr[-1], &fReducePts);
+ fCurrentContour->addQuad(quadStart);
+ } break;
+ case SkPath::kCubic_Verb: {
+ const SkPoint* cubicStart = &pointsPtr[-1];
+ reducedVerb = SkReduceOrder::Cubic(cubicStart, &fReducePts);
if (reducedVerb == 0) {
break; // skip degenerate points
}
if (reducedVerb == 1) {
- *fExtra.append() = fCurrentContour->addLine(fReducePts.end() - 2);
+ const SkPoint* lineStart = fReducePts.end() - 2;
+ *fExtra.append() = fCurrentContour->addLine(lineStart);
break;
}
if (reducedVerb == 2) {
- *fExtra.append() = fCurrentContour->addQuad(fReducePts.end() - 3);
+ const SkPoint* quadStart = fReducePts.end() - 3;
+ *fExtra.append() = fCurrentContour->addQuad(quadStart);
break;
}
- fCurrentContour->addCubic(&pointsPtr[-1]);
- break;
+ fCurrentContour->addCubic(cubicStart);
+ } break;
case SkPath::kClose_Verb:
SkASSERT(fCurrentContour);
- if (finalCurveStart && finalCurveEnd
- && *finalCurveStart != *finalCurveEnd) {
- *fReducePts.append() = *finalCurveStart;
- *fReducePts.append() = *finalCurveEnd;
- *fExtra.append() = fCurrentContour->addLine(fReducePts.end() - 2);
+ if (!close()) {
+ return false;
}
- complete();
continue;
default:
SkDEBUGFAIL("bad verb");
- return;
+ return false;
}
- finalCurveStart = &pointsPtr[verb - 1];
+ fFinalCurveStart = &pointsPtr[verb - 1];
pointsPtr += verb;
SkASSERT(fCurrentContour);
}
+ if (fCurrentContour && !fAllowOpenContours && !close()) {
+ return false;
+ }
+ return true;
}