Index: src/pathops/SkOpEdgeBuilder.cpp |
=================================================================== |
--- src/pathops/SkOpEdgeBuilder.cpp (revision 8862) |
+++ src/pathops/SkOpEdgeBuilder.cpp (working copy) |
@@ -28,8 +28,10 @@ |
preFetch(); |
} |
-void SkOpEdgeBuilder::finish() { |
- walk(); |
+bool SkOpEdgeBuilder::finish() { |
+ if (!walk()) { |
+ return false; |
+ } |
complete(); |
if (fCurrentContour && !fCurrentContour->segments().count()) { |
fContours.pop_back(); |
@@ -51,6 +53,7 @@ |
&fReducePts[rIndex]); |
} |
fExtra.reset(); // we're done with this |
+ return true; |
} |
// Note that copying the points here avoids copying the resulting path later. |
@@ -74,14 +77,73 @@ |
return fPathVerbs.count() - 1; |
} |
-void SkOpEdgeBuilder::walk() { |
+static bool is_finite_point(const SkPoint& pt) { |
+ // repeat logic in SkRect::isFinite() |
+ float accum = 0; |
+ accum *= pt.fX; |
+ accum *= pt.fY; |
+ |
+ // accum is either NaN or it is finite (zero). |
+ SkASSERT(0 == accum || !(accum == accum)); |
+ |
+ // value==value will be true iff value is not NaN |
+ // TODO: is it faster to say !accum or accum==accum? |
+ return accum == accum; |
+} |
+ |
+static bool is_finite_line(const SkPoint pts[2]) { |
+ // repeat logic in SkRect::isFinite() |
+ float accum = 0; |
+ accum *= pts[0].fX; |
+ accum *= pts[0].fY; |
+ accum *= pts[1].fX; |
+ accum *= pts[1].fY; |
+ |
+ // accum is either NaN or it is finite (zero). |
+ SkASSERT(0 == accum || !(accum == accum)); |
+ |
+ // value==value will be true iff value is not NaN |
+ // TODO: is it faster to say !accum or accum==accum? |
+ return accum == accum; |
+} |
+ |
+static bool is_finite_quad(const SkPoint pts[3]) { |
+ // repeat logic in SkRect::isFinite() |
+ float accum = 0; |
+ accum *= pts[0].fX; |
+ accum *= pts[0].fY; |
+ accum *= pts[1].fX; |
+ accum *= pts[1].fY; |
+ accum *= pts[2].fX; |
+ accum *= pts[2].fY; |
+ |
+ // accum is either NaN or it is finite (zero). |
+ SkASSERT(0 == accum || !(accum == accum)); |
+ |
+ // value==value will be true iff value is not NaN |
+ // TODO: is it faster to say !accum or accum==accum? |
+ return accum == accum; |
+} |
+ |
+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 +151,88 @@ |
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++; |
+ if (!is_finite_point(pointsPtr[0])) { |
reed1
2013/04/26 17:49:14
Would it be faster to just ask for the path's boun
caryclark
2013/04/26 19:47:30
Yes indeed. Done and uploaded.
On 2013/04/26 17:4
|
+ return false; |
+ } |
+ fFinalCurveEnd = pointsPtr++; |
continue; |
- case SkPath::kLine_Verb: |
+ case SkPath::kLine_Verb: { |
+ const SkPoint& lineEnd = pointsPtr[0]; |
+ if (!is_finite_point(lineEnd)) { |
+ return false; |
+ } |
+ 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: { |
+ if (!is_finite_line(pointsPtr)) { |
+ return false; |
+ } |
+ 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: { |
+ if (!is_finite_quad(pointsPtr)) { |
+ return false; |
+ } |
+ 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; |
} |