limit the number of points in SkDashPathEffect::asPoints

If the length of a line path is sufficiently long relative to the dash
interval, it is possible to cause SkDashPathEffect::asPoints to produce
so many points that it overflows the amount that can fit in an int type,
or otherwise produce non-finite values, i.e. path from (0,0) to (0,9e15)
with a dash interval of 1.

This fixes that by capping the amount of points to a sane limit - in this
case, 1mil, since that limit is also used in utils/SkDashPath.cpp and has
precedent.

Downstream Firefox bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=1287515

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2165013002

Review-Url: https://codereview.chromium.org/2165013002
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index 90af32e..30d7667 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -248,7 +248,14 @@
                 len2 -= clampedInitialDashLength; // skip initial partial empty
             }
         }
-        int numMidPoints = SkScalarFloorToInt(len2 / fIntervalLength);
+        // Too many midpoints can cause results->fNumPoints to overflow or
+        // otherwise cause the results->fPoints allocation below to OOM.
+        // Cap it to a sane value.
+        SkScalar numIntervals = len2 / fIntervalLength;
+        if (!SkScalarIsFinite(numIntervals) || numIntervals > SkDashPath::kMaxDashCount) {
+            return false;
+        }
+        int numMidPoints = SkScalarFloorToInt(numIntervals);
         results->fNumPoints += numMidPoints;
         len2 -= numMidPoints * fIntervalLength;
         bool partialLast = false;
diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp
index 8317d20..e06c2d2 100644
--- a/src/utils/SkDashPath.cpp
+++ b/src/utils/SkDashPath.cpp
@@ -176,6 +176,7 @@
         SkScalar ptCount = SkScalarMulDiv(pathLength,
                                           SkIntToScalar(intervalCount),
                                           intervalLength);
+        ptCount = SkTMin(ptCount, SkDashPath::kMaxDashCount);
         int n = SkScalarCeilToInt(ptCount) << 2;
         dst->incReserve(n);
 
@@ -255,7 +256,6 @@
         // 90 million dash segments and crashing the memory allocator. A limit of 1 million
         // segments seems reasonable: at 2 verbs per segment * 9 bytes per verb, this caps the
         // maximum dash memory overhead at roughly 17MB per path.
-        static const SkScalar kMaxDashCount = 1000000;
         dashCount += length * (count >> 1) / intervalLength;
         if (dashCount > kMaxDashCount) {
             dst->reset();
diff --git a/src/utils/SkDashPathPriv.h b/src/utils/SkDashPathPriv.h
index 1151281..752b59d 100644
--- a/src/utils/SkDashPathPriv.h
+++ b/src/utils/SkDashPathPriv.h
@@ -26,6 +26,8 @@
     bool FilterDashPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
                         const SkPathEffect::DashInfo& info);
 
+    const SkScalar kMaxDashCount = 1000000;
+
     /** See comments for InternalFilter */
     enum class StrokeRecApplication {
         kDisallow,