Use SkVertices for tessellated spot and ambient shadow rendering.

Change-Id: Ia81e7a771d345286533752708e4304c1ae3b97c9
Reviewed-on: https://skia-review.googlesource.com/8042
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Stan Iliev <stani@google.com>
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index b721f38..79567cc 100755
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -9,40 +9,50 @@
 #include "SkColorPriv.h"
 #include "SkGeometry.h"
 #include "SkPath.h"
+#include "SkVertices.h"
 
 #if SK_SUPPORT_GPU
 #include "GrPathUtils.h"
 #endif
 
-template <typename T> using UniqueArray = SkShadowVertices::UniqueArray<T>;
 
 /**
  * Base class
  */
-class SkShadowTessellator {
+class SkBaseShadowTessellator {
 public:
-    SkShadowTessellator(SkScalar radius, SkColor umbraColor,
-                        SkColor penumbraColor, bool transparent);
-    virtual ~SkShadowTessellator() {}
+    SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
+                            bool transparent);
+    virtual ~SkBaseShadowTessellator() {}
 
-    int vertexCount() const { return fPositions.count(); }
-    int indexCount() const { return fIndices.count(); }
-
-    bool succeeded() const { return fSucceeded; }
-
-    // The casts are needed to work around a, older GCC issue where the fact that the pointers are
-    // T* and not const T* causes calls to a deleted unique_ptr constructor.
-    UniqueArray<SkPoint> releasePositions() {
-        return UniqueArray<SkPoint>(static_cast<const SkPoint*>(fPositions.release()));
-    }
-    UniqueArray<SkColor> releaseColors() {
-        return UniqueArray<SkColor>(static_cast<const SkColor*>(fColors.release()));
-    }
-    UniqueArray<uint16_t> releaseIndices() {
-        return UniqueArray<uint16_t>(static_cast<const uint16_t*>(fIndices.release()));
+    sk_sp<SkVertices> releaseVertices() {
+        if (!fSucceeded) {
+            return nullptr;
+        }
+        int vCount = this->vertexCount();
+        int iCount = this->indexCount();
+        // We copy here for two reasons: 1) To tighten up our arrays and 2) to get into memory
+        // allocated by new[] rather than malloc.
+        // TODO: If we know we're not caching then we should avoid this.
+        SkPoint* positions = new SkPoint[vCount];
+        SkColor* colors = new SkColor[vCount];
+        uint16_t* indices = new uint16_t[iCount];
+        memcpy(positions, fPositions.begin(), sizeof(SkPoint) * vCount);
+        memcpy(colors, fColors.begin(), sizeof(SkColor) * vCount);
+        memcpy(indices, fIndices.begin(), sizeof(uint16_t) * iCount);
+        return SkVertices::MakeIndexed(SkCanvas::kTriangles_VertexMode,
+                                       std::unique_ptr<const SkPoint[]>(positions),
+                                       std::unique_ptr<const SkColor[]>(colors),
+                                       nullptr,
+                                       vCount,
+                                       std::unique_ptr<const uint16_t[]>(indices),
+                                       iCount);
     }
 
 protected:
+    int vertexCount() const { return fPositions.count(); }
+    int indexCount() const { return fIndices.count(); }
+
     virtual void handleLine(const SkPoint& p) = 0;
     void handleLine(const SkMatrix& m, SkPoint* p);
 
@@ -112,17 +122,16 @@
     *n = SkScalarFloorToInt(steps);
 }
 
-SkShadowTessellator::SkShadowTessellator(SkScalar radius, SkColor umbraColor,
-                                         SkColor penumbraColor, bool transparent)
-    : fFirstVertex(-1)
-    , fSucceeded(false)
-    , fTransparent(transparent)
-    , fUmbraColor(umbraColor)
-    , fPenumbraColor(penumbraColor)
-    , fRadius(radius)
-    , fDirection(1)
-    , fPrevUmbraIndex(-1) {
-
+SkBaseShadowTessellator::SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor,
+                                                 SkColor penumbraColor, bool transparent)
+        : fFirstVertex(-1)
+        , fSucceeded(false)
+        , fTransparent(transparent)
+        , fUmbraColor(umbraColor)
+        , fPenumbraColor(penumbraColor)
+        , fRadius(radius)
+        , fDirection(1)
+        , fPrevUmbraIndex(-1) {
     fInitPoints.setReserve(3);
 
     // child classes will set reserve for positions, colors and indices
@@ -133,12 +142,12 @@
 static const SkScalar kCubicTolerance = 0.2f;
 static const SkScalar kConicTolerance = 0.5f;
 
-void SkShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
+void SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
     m.mapPoints(p, 1);
     this->handleLine(*p);
 }
 
-void SkShadowTessellator::handleQuad(const SkPoint pts[3]) {
+void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
 #if SK_SUPPORT_GPU
     // TODO: Pull PathUtils out of Ganesh?
     int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
@@ -157,12 +166,12 @@
 #endif
 }
 
-void SkShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
+void SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
     m.mapPoints(pts, 3);
     this->handleQuad(pts);
 }
 
-void SkShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
+void SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
     m.mapPoints(pts, 4);
 #if SK_SUPPORT_GPU
     // TODO: Pull PathUtils out of Ganesh?
@@ -183,7 +192,7 @@
 #endif
 }
 
-void SkShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
+void SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
     m.mapPoints(pts, 3);
     SkAutoConicToQuads quadder;
     const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
@@ -200,7 +209,7 @@
     }
 }
 
-void SkShadowTessellator::addArc(const SkVector& nextNormal) {
+void SkBaseShadowTessellator::addArc(const SkVector& nextNormal) {
     // fill in fan from previous quad
     SkScalar rotSin, rotCos;
     int numSteps;
@@ -220,8 +229,8 @@
     }
 }
 
-void SkShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
-                                              const SkVector& nextNormal) {
+void SkBaseShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
+                                                  const SkVector& nextNormal) {
     // close out previous arc
     *fPositions.push() = fPrevPoint + nextNormal;
     *fColors.push() = fPenumbraColor;
@@ -235,7 +244,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
-class SkAmbientShadowTessellator : public SkShadowTessellator {
+class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
 public:
     SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
                                SkScalar radius, SkColor umbraColor,
@@ -247,7 +256,7 @@
 
     int                 fCentroidCount;
 
-    typedef SkShadowTessellator INHERITED;
+    typedef SkBaseShadowTessellator INHERITED;
 };
 
 SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
@@ -435,7 +444,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class SkSpotShadowTessellator : public SkShadowTessellator {
+class SkSpotShadowTessellator : public SkBaseShadowTessellator {
 public:
     SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
                             SkScalar scale, const SkVector& translate,
@@ -463,7 +472,7 @@
     bool                fFirstUmbraOutside;
     bool                fValidUmbra;
 
-    typedef SkShadowTessellator INHERITED;
+    typedef SkBaseShadowTessellator INHERITED;
 };
 
 SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
@@ -475,7 +484,6 @@
         , fPrevUmbraOutside(false)
         , fFirstUmbraOutside(false)
         , fValidUmbra(true) {
-    
     // TODO: calculate these better
     // Penumbra ring: 3*numPts
     // Umbra ring: numPts
@@ -948,33 +956,18 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-sk_sp<SkShadowVertices> SkShadowVertices::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
-                                                      SkScalar radius, SkColor umbra,
-                                                      SkColor penumbra, bool transparent) {
+sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
+                                                   SkScalar radius, SkColor umbra, SkColor penumbra,
+                                                   bool transparent) {
     SkAmbientShadowTessellator ambientTess(path, ctm, radius, umbra, penumbra, transparent);
-    if (!ambientTess.succeeded()) {
-        return nullptr;
-    }
-    int vcount = ambientTess.vertexCount();
-    int icount = ambientTess.indexCount();
-    return sk_sp<SkShadowVertices>(new SkShadowVertices(ambientTess.releasePositions(),
-                                                        ambientTess.releaseColors(),
-                                                        ambientTess.releaseIndices(), vcount,
-                                                        icount));
+    return ambientTess.releaseVertices();
 }
 
-sk_sp<SkShadowVertices> SkShadowVertices::MakeSpot(const SkPath& path, const SkMatrix& ctm,
-                                                   SkScalar scale, const SkVector& translate,
-                                                   SkScalar radius, SkColor umbraColor,
-                                                   SkColor penumbraColor, bool transparent) {
+sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
+                                                SkScalar scale, const SkVector& translate,
+                                                SkScalar radius, SkColor umbraColor,
+                                                SkColor penumbraColor, bool transparent) {
     SkSpotShadowTessellator spotTess(path, ctm, scale, translate, radius, umbraColor,
                                      penumbraColor, transparent);
-    if (!spotTess.succeeded()) {
-        return nullptr;
-    }
-    int vcount = spotTess.vertexCount();
-    int icount = spotTess.indexCount();
-    return sk_sp<SkShadowVertices>(new SkShadowVertices(spotTess.releasePositions(),
-                                                        spotTess.releaseColors(),
-                                                        spotTess.releaseIndices(), vcount, icount));
+    return spotTess.releaseVertices();
 }
diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h
index 875bb76..eb49bbe 100755
--- a/src/utils/SkShadowTessellator.h
+++ b/src/utils/SkShadowTessellator.h
@@ -8,68 +8,31 @@
 #ifndef SkShadowTessellator_DEFINED
 #define SkShadowTessellator_DEFINED
 
-#include "SkTDArray.h"
-#include "SkRefCnt.h"
-#include "SkPoint.h"
-
 #include "SkColor.h"
+#include "SkPoint.h"
+#include "SkRefCnt.h"
 
 class SkMatrix;
 class SkPath;
+class SkVertices;
 
-class SkShadowVertices : public SkRefCnt {
-public:
-    /**
-     * This function generates an ambient shadow mesh for a path by walking the path, outsetting by
-     * the radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively.
-     * If transparent is true, then the center of the ambient shadow will be filled in.
-     */
-    static sk_sp<SkShadowVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm,
-                                               SkScalar radius, SkColor umbraColor,
-                                               SkColor penumbraColor, bool transparent);
+namespace SkShadowTessellator {
+/**
+ * This function generates an ambient shadow mesh for a path by walking the path, outsetting by
+ * the radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively.
+ * If transparent is true, then the center of the ambient shadow will be filled in.
+ */
+sk_sp<SkVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm, SkScalar radius,
+                              SkColor umbraColor, SkColor penumbraColor, bool transparent);
 
-    /**
-     * This function generates a spot shadow mesh for a path by walking the transformed path,
-     * further transforming by the scale and translation, and outsetting and insetting by a radius.
-     * The center will be clipped against the original path unless transparent is true.
-     */
-    static sk_sp<SkShadowVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm,
-                                            SkScalar scale, const SkVector& translate,
-                                            SkScalar radius, SkColor umbraColor,
-                                            SkColor penumbraColor, bool transparent);
-
-    int vertexCount() const { return fVertexCnt; }
-    const SkPoint* positions() const { return fPositions.get(); }
-    const SkColor* colors() const { return fColors.get(); }
-
-    int indexCount() const { return fIndexCnt; }
-    const uint16_t* indices() const { return fIndices.get(); }
-
-    size_t size() const {
-        return sizeof(*this) + fVertexCnt * (sizeof(SkPoint) + sizeof(SkColor)) +
-               fIndexCnt * sizeof(uint16_t);
-    }
-
-private:
-    template<typename T> using Deleter = SkTDArray<SkPoint>::Deleter;
-    template<typename T> using UniqueArray = std::unique_ptr<const T[], Deleter<T>>;
-
-    SkShadowVertices(UniqueArray<SkPoint>&& positions, UniqueArray<SkColor>&& colors,
-                     UniqueArray<uint16_t>&& indices, int vertexCnt, int indexCnt)
-            : fVertexCnt(vertexCnt)
-            , fIndexCnt(indexCnt)
-            , fPositions(std::move(positions))
-            , fColors(std::move(colors))
-            , fIndices(std::move(indices)) {
-        SkASSERT(SkToBool(fPositions) && SkToBool(fColors) && SkToBool(vertexCnt) &&
-                 SkToBool(fIndices) && SkToBool(indexCnt));
-    }
-
-    int fVertexCnt;
-    int fIndexCnt;
-    UniqueArray<SkPoint> fPositions;
-    UniqueArray<SkColor> fColors;
-    UniqueArray<uint16_t> fIndices;
-};
+/**
+ * This function generates a spot shadow mesh for a path by walking the transformed path,
+ * further transforming by the scale and translation, and outsetting and insetting by a radius.
+ * The center will be clipped against the original path unless transparent is true.
+ */
+sk_sp<SkVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm, SkScalar scale,
+                           const SkVector& translate, SkScalar radius, SkColor umbraColor,
+                           SkColor penumbraColor, bool transparent);
+}
 
 #endif
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index c4b4e3d..8374aef 100755
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -13,6 +13,7 @@
 #include "SkResourceCache.h"
 #include "SkShadowTessellator.h"
 #include "SkTLazy.h"
+#include "SkVertices.h"
 #if SK_SUPPORT_GPU
 #include "GrShape.h"
 #include "effects/GrBlurredEdgeFragmentProcessor.h"
@@ -98,9 +99,9 @@
         return true;
     }
 
-    sk_sp<SkShadowVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
-        return SkShadowVertices::MakeAmbient(path, ctm, fRadius, fUmbraColor, fPenumbraColor,
-                                             fTransparent);
+    sk_sp<SkVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
+        return SkShadowTessellator::MakeAmbient(path, ctm, fRadius, fUmbraColor, fPenumbraColor,
+                                                fTransparent);
     }
 };
 
@@ -148,10 +149,10 @@
         return false;
     }
 
-    sk_sp<SkShadowVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
+    sk_sp<SkVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
         bool transparent = OccluderType::kTransparent == fOccluderType;
-        return SkShadowVertices::MakeSpot(path, ctm, fScale, fOffset, fRadius, fUmbraColor,
-                                          fPenumbraColor, transparent);
+        return SkShadowTessellator::MakeSpot(path, ctm, fScale, fOffset, fRadius, fUmbraColor,
+                                             fPenumbraColor, transparent);
     }
 };
 
@@ -165,23 +166,23 @@
 public:
     size_t size() const { return fAmbientSet.size() + fSpotSet.size(); }
 
-    sk_sp<SkShadowVertices> find(const AmbientVerticesFactory& ambient, const SkMatrix& matrix,
-                                 SkVector* translate) const {
+    sk_sp<SkVertices> find(const AmbientVerticesFactory& ambient, const SkMatrix& matrix,
+                           SkVector* translate) const {
         return fAmbientSet.find(ambient, matrix, translate);
     }
 
-    sk_sp<SkShadowVertices> add(const SkPath& devPath, const AmbientVerticesFactory& ambient,
-                                const SkMatrix& matrix) {
+    sk_sp<SkVertices> add(const SkPath& devPath, const AmbientVerticesFactory& ambient,
+                          const SkMatrix& matrix) {
         return fAmbientSet.add(devPath, ambient, matrix);
     }
 
-    sk_sp<SkShadowVertices> find(const SpotVerticesFactory& spot, const SkMatrix& matrix,
-                                 SkVector* translate) const {
+    sk_sp<SkVertices> find(const SpotVerticesFactory& spot, const SkMatrix& matrix,
+                           SkVector* translate) const {
         return fSpotSet.find(spot, matrix, translate);
     }
 
-    sk_sp<SkShadowVertices> add(const SkPath& devPath, const SpotVerticesFactory& spot,
-                                const SkMatrix& matrix) {
+    sk_sp<SkVertices> add(const SkPath& devPath, const SpotVerticesFactory& spot,
+                          const SkMatrix& matrix) {
         return fSpotSet.add(devPath, spot, matrix);
     }
 
@@ -191,8 +192,8 @@
     public:
         size_t size() const { return fSize; }
 
-        sk_sp<SkShadowVertices> find(const FACTORY& factory, const SkMatrix& matrix,
-                                     SkVector* translate) const {
+        sk_sp<SkVertices> find(const FACTORY& factory, const SkMatrix& matrix,
+                               SkVector* translate) const {
             for (int i = 0; i < MAX_ENTRIES; ++i) {
                 if (fEntries[i].fFactory.isCompatible(factory, translate)) {
                     const SkMatrix& m = fEntries[i].fMatrix;
@@ -214,9 +215,8 @@
             return nullptr;
         }
 
-        sk_sp<SkShadowVertices> add(const SkPath& devPath, const FACTORY& factory,
-                                    const SkMatrix& matrix) {
-            sk_sp<SkShadowVertices> vertices = factory.makeVertices(devPath, matrix);
+        sk_sp<SkVertices> add(const SkPath& path, const FACTORY& factory, const SkMatrix& matrix) {
+            sk_sp<SkVertices> vertices = factory.makeVertices(path, matrix);
             if (!vertices) {
                 return nullptr;
             }
@@ -237,7 +237,7 @@
     private:
         struct Entry {
             FACTORY fFactory;
-            sk_sp<SkShadowVertices> fVertices;
+            sk_sp<SkVertices> fVertices;
             SkMatrix fMatrix;
         };
         Entry fEntries[MAX_ENTRIES];
@@ -277,8 +277,8 @@
     sk_sp<CachedTessellations> refTessellations() const { return fTessellations; }
 
     template <typename FACTORY>
-    sk_sp<SkShadowVertices> find(const FACTORY& factory, const SkMatrix& matrix,
-                                 SkVector* translate) const {
+    sk_sp<SkVertices> find(const FACTORY& factory, const SkMatrix& matrix,
+                           SkVector* translate) const {
         return fTessellations->find(factory, matrix, translate);
     }
 
@@ -300,7 +300,7 @@
     const SkMatrix* const fViewMatrix;
     // If this is valid after Find is called then we found the vertices and they should be drawn
     // with fTranslate applied.
-    sk_sp<SkShadowVertices> fVertices;
+    sk_sp<SkVertices> fVertices;
     SkVector fTranslate = {0, 0};
 
     // If this is valid after Find then the caller should add the vertices to the tessellation set
@@ -385,7 +385,7 @@
         SkResourceCache::Find(*key, FindVisitor<FACTORY>, &context);
     }
 
-    sk_sp<SkShadowVertices> vertices;
+    sk_sp<SkVertices> vertices;
     const SkVector* translate;
     static constexpr SkVector kZeroTranslate = {0, 0};
     bool foundInCache = SkToBool(context.fVertices);
@@ -426,9 +426,7 @@
         canvas->save();
         canvas->translate(translate->fX, translate->fY);
     }
-    canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertices->vertexCount(),
-                         vertices->positions(), nullptr, vertices->colors(), vertices->indices(),
-                         vertices->indexCount(), paint);
+    canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
     if (translate->fX || translate->fY) {
         canvas->restore();
     }