ccpr: Clamp the number of linear stroke segments

Clamps the number of linear segments before indexing into arrays with
it (oops). Also adds some minor fixups surrounding NaNs.

Bug: skia:8360
Change-Id: Id520ac49df2ebce71bda9fcaa0f164ddb6ddf2d2
Reviewed-on: https://skia-review.googlesource.com/154771
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp
index 005629e..b6c3a08 100644
--- a/src/core/SkGeometry.cpp
+++ b/src/core/SkGeometry.cpp
@@ -274,7 +274,7 @@
         return 1;
     }
     SkScalar t = numer / denom;
-    SkASSERT(0 <= t && t < 1);
+    SkASSERT((0 <= t && t < 1) || SkScalarIsNaN(t));
     return t;
 }
 
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index a24cd67..7b63f04 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -205,7 +205,7 @@
     return &fCopyAtlasStack.current();
 }
 
-static void transform_path_pts(const SkMatrix& m, const SkPath& path,
+static bool transform_path_pts(const SkMatrix& m, const SkPath& path,
                                const SkAutoSTArray<32, SkPoint>& outDevPts, SkRect* devBounds,
                                SkRect* devBounds45) {
     const SkPoint* pts = SkPathPriv::PointData(path);
@@ -246,6 +246,11 @@
         devPt.store(&outDevPts[i]);
     }
 
+    if (!(Sk4f(0) == topLeft*0).allTrue() || !(Sk4f(0) == bottomRight*0).allTrue()) {
+        // The bounds are infinite or NaN.
+        return false;
+    }
+
     SkPoint topLeftPts[2], bottomRightPts[2];
     topLeft.store(topLeftPts);
     bottomRight.store(bottomRightPts);
@@ -253,6 +258,7 @@
                        bottomRightPts[0].y());
     devBounds45->setLTRB(topLeftPts[1].x(), topLeftPts[1].y(), bottomRightPts[1].x(),
                          bottomRightPts[1].y());
+    return true;
 }
 
 const GrCCAtlas* GrCCPerFlushResources::renderShapeInAtlas(
@@ -267,7 +273,11 @@
         SkDEBUGCODE(--fEndPathInstance);
         return nullptr;
     }
-    transform_path_pts(m, path, fLocalDevPtsBuffer, devBounds, devBounds45);
+    if (!transform_path_pts(m, path, fLocalDevPtsBuffer, devBounds, devBounds45)) {
+        // The transformed path had infinite or NaN bounds.
+        SkDEBUGCODE(--fEndPathInstance);
+        return nullptr;
+    }
 
     const SkStrokeRec& stroke = shape.style().strokeRec();
     if (!stroke.isFillStyle()) {
diff --git a/src/gpu/ccpr/GrCCStrokeGeometry.cpp b/src/gpu/ccpr/GrCCStrokeGeometry.cpp
index 3fcafec..ec626b0 100644
--- a/src/gpu/ccpr/GrCCStrokeGeometry.cpp
+++ b/src/gpu/ccpr/GrCCStrokeGeometry.cpp
@@ -156,6 +156,7 @@
 
     // Decide how many flat line segments to chop the curve into.
     int numSegments = wangs_formula_quadratic(p0, p1, p2);
+    numSegments = SkTMin(numSegments, 1 << kMaxNumLinearSegmentsLog2);
     if (numSegments <= 1) {
         this->rotateTo(leftJoinVerb, normals[0]);
         this->lineTo(Verb::kInternalRoundJoin, P[2]);
@@ -283,6 +284,7 @@
 
     // Decide how many flat line segments to chop the curve into.
     int numSegments = wangs_formula_cubic(p0, p1, p2, p3);
+    numSegments = SkTMin(numSegments, 1 << kMaxNumLinearSegmentsLog2);
     if (numSegments <= 1) {
         this->rotateTo(leftJoinVerb, normals[0]);
         this->lineTo(leftJoinVerb, P[3]);
diff --git a/src/gpu/ccpr/GrCCStroker.cpp b/src/gpu/ccpr/GrCCStroker.cpp
index ab3906c..919e0f7 100644
--- a/src/gpu/ccpr/GrCCStroker.cpp
+++ b/src/gpu/ccpr/GrCCStroker.cpp
@@ -476,7 +476,7 @@
 
         // For miter and round joins, we place an additional triangle cap on top of the bevel. This
         // triangle is literal for miters and is conic control points for round joins.
-        SkASSERT(miterCapHeightOverWidth >= 0);
+        SkASSERT(miterCapHeightOverWidth >= 0 || SkScalarIsNaN(miterCapHeightOverWidth));
         Sk2f base = n1 - n0;
         Sk2f baseNorm = Sk2f(base[1], -base[0]);
         Sk2f c = (n0 + n1) * .5f + baseNorm * miterCapHeightOverWidth;