diff options
-rw-r--r-- | gm/beziereffects.cpp | 5 | ||||
-rw-r--r-- | samplecode/SampleAAGeometry.cpp | 11 | ||||
-rw-r--r-- | src/core/SkGeometry.cpp | 24 | ||||
-rw-r--r-- | src/core/SkGeometry.h | 2 | ||||
-rw-r--r-- | src/core/SkPathMeasure.cpp | 10 | ||||
-rw-r--r-- | src/gpu/batches/GrAAHairLinePathRenderer.cpp | 5 | ||||
-rw-r--r-- | src/pathops/SkOpEdgeBuilder.cpp | 6 | ||||
-rw-r--r-- | tests/PathOpsConicIntersectionTest.cpp | 4 | ||||
-rw-r--r-- | tests/PathOpsOpTest.cpp | 22 |
9 files changed, 70 insertions, 19 deletions
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp index 42be080ae3..3dd4d65f7f 100644 --- a/gm/beziereffects.cpp +++ b/gm/beziereffects.cpp @@ -353,7 +353,10 @@ private: if (dst) { SkConic conic; conic.set(src, weight); - conic.chopAt(t, dst); + if (!conic.chopAt(t, dst)) { + dst[0].set(src, weight); + return 1; + } } return 2; } diff --git a/samplecode/SampleAAGeometry.cpp b/samplecode/SampleAAGeometry.cpp index 7d873032e4..4b7a37420b 100644 --- a/samplecode/SampleAAGeometry.cpp +++ b/samplecode/SampleAAGeometry.cpp @@ -220,7 +220,9 @@ static void add_path_segment(int index, SkPath* path) { SkConic chop[2]; SkConic conic; conic.set(pts, iter.conicWeight()); - conic.chopAt(0.5f, chop); + if (!conic.chopAt(0.5f, chop)) { + return; + } result.conicTo(chop[0].fPts[1], chop[0].fPts[2], chop[0].fW); pts[1] = chop[1].fPts[1]; weight = chop[1].fW; @@ -1360,9 +1362,10 @@ public: SkConic split[2]; SkConic conic; conic.set(pts, weight); - conic.chopAt(0.5f, split); - conic_coverage(split[0].fPts, split[0].fW, distanceMap, w, h); - conic_coverage(split[1].fPts, split[1].fW, distanceMap, w, h); + if (conic.chopAt(0.5f, split)) { + conic_coverage(split[0].fPts, split[0].fW, distanceMap, w, h); + conic_coverage(split[1].fPts, split[1].fW, distanceMap, w, h); + } } void cubic_coverage(SkPoint pts[4], uint8_t* distanceMap, int w, int h) { diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index 027b65f0f1..cb515e1d14 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -975,7 +975,8 @@ static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) { dst[2].set(src[2].fX * 1, src[2].fY * 1, 1); } -void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { +// return false if infinity or NaN is generated; caller must check +bool SkConic::chopAt(SkScalar t, SkConic dst[2]) const { SkP3D tmp[3], tmp2[3]; ratquad_mapTo3D(fPts, fW, tmp); @@ -1001,18 +1002,23 @@ void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { SkScalar root = SkScalarSqrt(tmp2[1].fZ); dst[0].fW = tmp2[0].fZ / root; dst[1].fW = tmp2[2].fZ / root; + SkASSERT(sizeof(dst[0]) == sizeof(SkScalar) * 7); + SkASSERT(0 == offsetof(SkConic, fPts[0].fX)); + return SkScalarsAreFinite(&dst[0].fPts[0].fX, 7 * 2); } void SkConic::chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const { if (0 == t1 || 1 == t2) { if (0 == t1 && 1 == t2) { *dst = *this; + return; } else { SkConic pair[2]; - this->chopAt(t1 ? t1 : t2, pair); - *dst = pair[SkToBool(t1)]; + if (this->chopAt(t1 ? t1 : t2, pair)) { + *dst = pair[SkToBool(t1)]; + return; + } } - return; } SkConicCoeff coeff(*this); Sk2s tt1(t1); @@ -1243,7 +1249,10 @@ bool SkConic::findYExtrema(SkScalar* t) const { bool SkConic::chopAtXExtrema(SkConic dst[2]) const { SkScalar t; if (this->findXExtrema(&t)) { - this->chopAt(t, dst); + if (!this->chopAt(t, dst)) { + // if chop can't return finite values, don't chop + return false; + } // now clean-up the middle, since we know t was meant to be at // an X-extrema SkScalar value = dst[0].fPts[2].fX; @@ -1258,7 +1267,10 @@ bool SkConic::chopAtXExtrema(SkConic dst[2]) const { bool SkConic::chopAtYExtrema(SkConic dst[2]) const { SkScalar t; if (this->findYExtrema(&t)) { - this->chopAt(t, dst); + if (!this->chopAt(t, dst)) { + // if chop can't return finite values, don't chop + return false; + } // now clean-up the middle, since we know t was meant to be at // an Y-extrema SkScalar value = dst[0].fPts[2].fY; diff --git a/src/core/SkGeometry.h b/src/core/SkGeometry.h index 74c9d89e3f..55d763b967 100644 --- a/src/core/SkGeometry.h +++ b/src/core/SkGeometry.h @@ -215,7 +215,7 @@ struct SkConic { * be used. */ void evalAt(SkScalar t, SkPoint* pos, SkVector* tangent = nullptr) const; - void chopAt(SkScalar t, SkConic dst[2]) const; + bool SK_WARN_UNUSED_RESULT chopAt(SkScalar t, SkConic dst[2]) const; void chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const; void chop(SkConic dst[2]) const; diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp index 8582bc2b73..05d14d647c 100644 --- a/src/core/SkPathMeasure.cpp +++ b/src/core/SkPathMeasure.cpp @@ -85,14 +85,16 @@ void SkPathMeasure_segTo(const SkPoint pts[], unsigned segType, dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); } else { SkConic tmp[2]; - conic.chopAt(stopT, tmp); - dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); + if (conic.chopAt(stopT, tmp)) { + dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); + } } } else { if (SK_Scalar1 == stopT) { SkConic tmp1[2]; - conic.chopAt(startT, tmp1); - dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); + if (conic.chopAt(startT, tmp1)) { + dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); + } } else { SkConic tmp; conic.chopAt(startT, stopT, &tmp); diff --git a/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/src/gpu/batches/GrAAHairLinePathRenderer.cpp index 194c79e41e..9d73cf4f17 100644 --- a/src/gpu/batches/GrAAHairLinePathRenderer.cpp +++ b/src/gpu/batches/GrAAHairLinePathRenderer.cpp @@ -145,7 +145,10 @@ static int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weig if (dst) { SkConic conic; conic.set(src, weight); - conic.chopAt(t, dst); + if (!conic.chopAt(t, dst)) { + dst[0].set(src, weight); + return 1; + } } return 2; } diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp index c304357575..7fc7d7213d 100644 --- a/src/pathops/SkOpEdgeBuilder.cpp +++ b/src/pathops/SkOpEdgeBuilder.cpp @@ -231,7 +231,11 @@ bool SkOpEdgeBuilder::walk() { if (maxCurvature > 0) { SkConic conic(pointsPtr, weight); SkConic pair[2]; - conic.chopAt(maxCurvature, pair); + if (!conic.chopAt(maxCurvature, pair)) { + // if result can't be computed, use original + fCurrentContour->addConic(pointsPtr, weight); + break; + } SkPoint cStorage[2][3]; SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]); SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]); diff --git a/tests/PathOpsConicIntersectionTest.cpp b/tests/PathOpsConicIntersectionTest.cpp index 624a68adaf..e22ad6bff1 100644 --- a/tests/PathOpsConicIntersectionTest.cpp +++ b/tests/PathOpsConicIntersectionTest.cpp @@ -165,7 +165,9 @@ static void chopBothWays(const SkDConic& dConic, double t, const char* name) { conic.fW = dConic.fWeight; SkConic chopped[2]; SkDConic dChopped[2]; - conic.chopAt(SkDoubleToScalar(t), chopped); + if (!conic.chopAt(SkDoubleToScalar(t), chopped)) { + return; + } dChopped[0] = dConic.subDivide(0, t); dChopped[1] = dConic.subDivide(t, 1); #if DEBUG_VISUALIZE_CONICS diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp index 92ef105ce8..5cd0e75501 100644 --- a/tests/PathOpsOpTest.cpp +++ b/tests/PathOpsOpTest.cpp @@ -7915,7 +7915,29 @@ path.cubicTo(SkBits2Float(0x6d06f06a), SkBits2Float(0xe30465cf), SkBits2Float(0x testPathOpFuzz(reporter, path1, path2, (SkPathOp) 4, filename); } +static void fuzz763_44(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 1); +path.moveTo(SkBits2Float(0x7c223bab), SkBits2Float(0x7cf35966)); // 3.36945e+36f, 1.01083e+37f +path.quadTo(SkBits2Float(0x00000000), SkBits2Float(0x7ccaca6d), SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 8.4236e+36f, 0, 0 +path.lineTo(SkBits2Float(0x7d7d7d7d), SkBits2Float(0x00000000)); // 2.10591e+37f, 0 +path.quadTo(SkBits2Float(0x7ccacab0), SkBits2Float(0x7d1817f4), SkBits2Float(0x7c223bab), SkBits2Float(0x7cf35966)); // 8.42364e+36f, 1.26354e+37f, 3.36945e+36f, 1.01083e+37f +path.close(); + + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x109d0000), SkBits2Float(0xff7bc000)); // 6.19256e-29f, -3.34633e+38f +path.conicTo(SkBits2Float(0x979797ed), SkBits2Float(0x3a214797), SkBits2Float(0x28aa217a), SkBits2Float(0x01007272), SkBits2Float(0x00000072)); // -9.7965e-25f, 0.000615233f, 1.88883e-14f, 2.3592e-38f, 1.59748e-43f +path.quadTo(SkBits2Float(0x72728302), SkBits2Float(0x8b727272), SkBits2Float(0x72727272), SkBits2Float(0xc00308f6)); // 4.80344e+30f, -4.66936e-32f, 4.80216e+30f, -2.04742f +path.conicTo(SkBits2Float(0x7f52753a), SkBits2Float(0x8072ffff), SkBits2Float(0x67af2103), SkBits2Float(0x7d2a6847), SkBits2Float(0x7d7d7d7d)); // 2.79747e+38f, -1.05611e-38f, 1.65405e+24f, 1.41569e+37f, 2.10591e+37f + + SkPath path2(path); + testPathOpFuzz(reporter, path1, path2, (SkPathOp) 3, filename); +} + static struct TestDesc failTests[] = { + TEST(fuzz763_44), TEST(fuzz763_43), TEST(fuzz763_42), TEST(fuzz763_41), |