Some more shadow cleanup

Bug: oss-fuzz:10382, oss-fuzz:10399
Change-Id: Ifc3d70fd9f0eb6fb2a862dfd5b087167575330cf
Reviewed-on: https://skia-review.googlesource.com/154821
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index 943ff05..151f948 100644
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -55,9 +55,10 @@
     void computeClipVectorsAndTestCentroid();
     bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
     void addEdge(const SkVector& nextPoint, const SkVector& nextNormal, SkColor umbraColor,
-                 bool lastEdge, bool doClip);
-    bool addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, int* currUmbraIndex);
-    int getClosestUmbraPoint(const SkPoint& point);
+                 const SkTDArray<SkPoint>& umbraPolygon, bool lastEdge, bool doClip);
+    bool addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
+                       const SkTDArray<SkPoint>& umbraPolygon, int* currUmbraIndex);
+    int getClosestUmbraIndex(const SkPoint& point, const SkTDArray<SkPoint>& umbraPolygon);
 
     // concave shadow methods
     bool computeConcaveShadow(SkScalar inset, SkScalar outset);
@@ -94,10 +95,9 @@
     SkTDArray<SkColor>  fColors;
     SkTDArray<uint16_t> fIndices;
 
-    SkTDArray<SkPoint>  fPathPolygon;
-    SkTDArray<SkPoint>  fUmbraPolygon;
-    SkTDArray<SkPoint>  fClipPolygon;
-    SkTDArray<SkVector> fClipVectors;
+    SkTDArray<SkPoint>   fPathPolygon;
+    SkTDArray<SkPoint>   fClipPolygon;
+    SkTDArray<SkVector>  fClipVectors;
 
     SkPoint             fCentroid;
     SkScalar            fArea;
@@ -268,23 +268,29 @@
             minDistSq = distSq;
         }
     }
-    static constexpr auto kTolerance = 1.0e-2f;
-    if (minDistSq < (inset + kTolerance)*(inset + kTolerance)) {
-        // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
-        auto newInset = SkScalarSqrt(minDistSq) - kTolerance;
-        auto ratio = 128 * (newInset/inset + 1);
-        SkASSERT(SkScalarIsFinite(ratio));
-        // they aren't PMColors, but the interpolation algorithm is the same
-        umbraColor = SkPMLerp(kUmbraColor, kPenumbraColor, (unsigned)ratio);
-        inset = newInset;
-    }
 
-    // generate inner ring
-    if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), inset,
-                              &fUmbraPolygon)) {
-        // not ideal, but in this case we'll inset using the centroid
-        fValidUmbra = false;
+    SkTDArray<SkPoint> insetPolygon;
+    if (inset > SK_ScalarNearlyZero) {
+        static constexpr auto kTolerance = 1.0e-2f;
+        if (minDistSq < (inset + kTolerance)*(inset + kTolerance)) {
+            // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
+            auto newInset = SkScalarSqrt(minDistSq) - kTolerance;
+            auto ratio = 128 * (newInset / inset + 1);
+            SkASSERT(SkScalarIsFinite(ratio));
+            // they aren't PMColors, but the interpolation algorithm is the same
+            umbraColor = SkPMLerp(kUmbraColor, kPenumbraColor, (unsigned)ratio);
+            inset = newInset;
+        }
+
+        // generate inner ring
+        if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), inset,
+                                  &insetPolygon)) {
+            // not ideal, but in this case we'll inset using the centroid
+            fValidUmbra = false;
+        }
     }
+    const SkTDArray<SkPoint>& umbraPolygon = (inset > SK_ScalarNearlyZero) ? insetPolygon
+                                                                           : fPathPolygon;
 
     // walk around the path polygon, generate outer ring and connect to inner ring
     if (fTransparent) {
@@ -308,7 +314,7 @@
     fPrevPoint = fFirstPoint;
     fPrevUmbraIndex = -1;
 
-    this->addInnerPoint(fFirstPoint, umbraColor, &fPrevUmbraIndex);
+    this->addInnerPoint(fFirstPoint, umbraColor, umbraPolygon, &fPrevUmbraIndex);
 
     if (!fTransparent && doClip) {
         SkPoint clipPoint;
@@ -325,7 +331,7 @@
     SkPoint newPoint = fFirstPoint + fFirstOutset;
     fPositions.push_back(newPoint);
     fColors.push_back(kPenumbraColor);
-    this->addEdge(fPathPolygon[0], fFirstOutset, umbraColor, false, doClip);
+    this->addEdge(fPathPolygon[0], fFirstOutset, umbraColor, umbraPolygon, false, doClip);
 
     for (int i = 1; i < polyCount; ++i) {
         SkVector normal;
@@ -334,7 +340,8 @@
         }
         normal *= outset;
         this->addArc(normal, outset, true);
-        this->addEdge(fPathPolygon[i], normal, umbraColor, i == polyCount - 1, doClip);
+        this->addEdge(fPathPolygon[i], normal, umbraColor, umbraPolygon,
+                      i == polyCount - 1, doClip);
     }
     SkASSERT(this->indexCount());
 
@@ -390,7 +397,8 @@
 }
 
 void SkBaseShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal,
-                                      SkColor umbraColor, bool lastEdge, bool doClip) {
+                                      SkColor umbraColor, const SkTDArray<SkPoint>& umbraPolygon,
+                                      bool lastEdge, bool doClip) {
     // add next umbra point
     int currUmbraIndex;
     bool duplicate;
@@ -399,7 +407,7 @@
         currUmbraIndex = fFirstVertexIndex;
         fPrevPoint = nextPoint;
     } else {
-        duplicate = this->addInnerPoint(nextPoint, umbraColor, &currUmbraIndex);
+        duplicate = this->addInnerPoint(nextPoint, umbraColor, umbraPolygon, &currUmbraIndex);
     }
     int prevPenumbraIndex = duplicate || (currUmbraIndex == fFirstVertexIndex)
         ? fPositions.count() - 1
@@ -481,6 +489,7 @@
 }
 
 bool SkBaseShadowTessellator::addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
+                                            const SkTDArray<SkPoint>& umbraPolygon,
                                             int* currUmbraIndex) {
     SkPoint umbraPoint;
     if (!fValidUmbra) {
@@ -488,7 +497,7 @@
         v *= 0.95f;
         umbraPoint = pathPoint + v;
     } else {
-        umbraPoint = fUmbraPolygon[this->getClosestUmbraPoint(pathPoint)];
+        umbraPoint = umbraPolygon[this->getClosestUmbraIndex(pathPoint, umbraPolygon)];
     }
 
     fPrevPoint = pathPoint;
@@ -511,29 +520,30 @@
     }
 }
 
-int SkBaseShadowTessellator::getClosestUmbraPoint(const SkPoint& p) {
-    SkScalar minDistance = SkPointPriv::DistanceToSqd(p, fUmbraPolygon[fCurrUmbraIndex]);
+int SkBaseShadowTessellator::getClosestUmbraIndex(const SkPoint& p,
+                                                  const SkTDArray<SkPoint>& umbraPolygon) {
+    SkScalar minDistance = SkPointPriv::DistanceToSqd(p, umbraPolygon[fCurrUmbraIndex]);
     int index = fCurrUmbraIndex;
     int dir = 1;
-    int next = (index + dir) % fUmbraPolygon.count();
+    int next = (index + dir) % umbraPolygon.count();
 
     // init travel direction
-    SkScalar distance = SkPointPriv::DistanceToSqd(p, fUmbraPolygon[next]);
+    SkScalar distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
     if (distance < minDistance) {
         index = next;
         minDistance = distance;
     } else {
-        dir = fUmbraPolygon.count() - 1;
+        dir = umbraPolygon.count() - 1;
     }
 
     // iterate until we find a point that increases the distance
-    next = (index + dir) % fUmbraPolygon.count();
-    distance = SkPointPriv::DistanceToSqd(p, fUmbraPolygon[next]);
+    next = (index + dir) % umbraPolygon.count();
+    distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
     while (distance < minDistance) {
         index = next;
         minDistance = distance;
-        next = (index + dir) % fUmbraPolygon.count();
-        distance = SkPointPriv::DistanceToSqd(p, fUmbraPolygon[next]);
+        next = (index + dir) % umbraPolygon.count();
+        distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
     }
 
     fCurrUmbraIndex = index;
@@ -546,10 +556,11 @@
     }
 
     // generate inner ring
+    SkTDArray<SkPoint> umbraPolygon;
     SkTDArray<int> umbraIndices;
     umbraIndices.setReserve(fPathPolygon.count());
     if (!SkOffsetSimplePolygon(&fPathPolygon[0], fPathPolygon.count(), inset,
-                               &fUmbraPolygon, &umbraIndices)) {
+                               &umbraPolygon, &umbraIndices)) {
         // TODO: figure out how to handle this case
         return false;
     }
@@ -557,20 +568,20 @@
     // generate outer ring
     SkTDArray<SkPoint> penumbraPolygon;
     SkTDArray<int> penumbraIndices;
-    penumbraPolygon.setReserve(fUmbraPolygon.count());
-    penumbraIndices.setReserve(fUmbraPolygon.count());
+    penumbraPolygon.setReserve(umbraPolygon.count());
+    penumbraIndices.setReserve(umbraPolygon.count());
     if (!SkOffsetSimplePolygon(&fPathPolygon[0], fPathPolygon.count(), -outset,
                                &penumbraPolygon, &penumbraIndices)) {
         // TODO: figure out how to handle this case
         return false;
     }
 
-    if (!fUmbraPolygon.count() || !penumbraPolygon.count()) {
+    if (!umbraPolygon.count() || !penumbraPolygon.count()) {
         return false;
     }
 
     // attach the rings together
-    this->stitchConcaveRings(fUmbraPolygon, &umbraIndices, penumbraPolygon, &penumbraIndices);
+    this->stitchConcaveRings(umbraPolygon, &umbraIndices, penumbraPolygon, &penumbraIndices);
 
     return true;
 }
@@ -739,6 +750,10 @@
                             pSanitized)) {
             // remove collinear point
             fPathPolygon.pop();
+            // it's possible that the previous point is coincident with the new one now
+            if (duplicate_pt(fPathPolygon[fPathPolygon.count() - 1], pSanitized)) {
+                fPathPolygon.pop();
+            }
         }
     }