aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/beziereffects.cpp5
-rw-r--r--samplecode/SampleAAGeometry.cpp11
-rw-r--r--src/core/SkGeometry.cpp24
-rw-r--r--src/core/SkGeometry.h2
-rw-r--r--src/core/SkPathMeasure.cpp10
-rw-r--r--src/gpu/batches/GrAAHairLinePathRenderer.cpp5
-rw-r--r--src/pathops/SkOpEdgeBuilder.cpp6
-rw-r--r--tests/PathOpsConicIntersectionTest.cpp4
-rw-r--r--tests/PathOpsOpTest.cpp22
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),