Make SkShadowUtils tessellations ref counted in preparation for caching them.
Change-Id: I60133fcc4101a27bcc3e7ad38e7348ad9147b8a9
Reviewed-on: https://skia-review.googlesource.com/7784
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/include/private/SkTDArray.h b/include/private/SkTDArray.h
index f71d357..16f8474 100644
--- a/include/private/SkTDArray.h
+++ b/include/private/SkTDArray.h
@@ -72,6 +72,12 @@
SkTSwap(fCount, other.fCount);
}
+ // The deleter that ought to be used for a std:: smart pointer that takes ownership from
+ // release().
+ struct Deleter {
+ void operator()(const void* p) { sk_free((void*)p); }
+ };
+
/** Return a ptr to the array of data, to be freed with sk_free. This also
resets the SkTDArray to be empty.
*/
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index ca8927b..147ff53 100755
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -13,6 +13,57 @@
#include "GrPathUtils.h"
#endif
+template <typename T> using UniqueArray = SkShadowVertices::UniqueArray<T>;
+
+// TODO: derive the ambient and spot classes from a base class containing common elements
+
+class SkAmbientShadowTessellator {
+public:
+ SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor,
+ SkColor penumbraColor, bool transparent);
+
+ int vertexCount() const { return fPositions.count(); }
+ int indexCount() const { return fIndices.count(); }
+
+ UniqueArray<SkPoint> releasePositions() { return UniqueArray<SkPoint>(fPositions.release()); }
+ UniqueArray<SkColor> releaseColors() { return UniqueArray<SkColor>(fColors.release()); }
+ UniqueArray<uint16_t> releaseIndices() { return UniqueArray<uint16_t>(fIndices.release()); }
+
+private:
+ void handleLine(const SkPoint& p);
+
+ void handleQuad(const SkPoint pts[3]);
+
+ void handleCubic(SkPoint pts[4]);
+
+ void handleConic(SkPoint pts[3], SkScalar w);
+
+ void addArc(const SkVector& nextNormal);
+ void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
+ void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
+
+ SkScalar fRadius;
+ SkColor fUmbraColor;
+ SkColor fPenumbraColor;
+ bool fTransparent;
+
+ SkTDArray<SkPoint> fPositions;
+ SkTDArray<SkColor> fColors;
+ SkTDArray<uint16_t> fIndices;
+
+ int fPrevInnerIndex;
+ SkVector fPrevNormal;
+ int fFirstVertex;
+ SkVector fFirstNormal;
+ SkScalar fDirection;
+ int fCentroidCount;
+
+ // first three points
+ SkTDArray<SkPoint> fInitPoints;
+ // temporary buffer
+ SkTDArray<SkPoint> fPointBuffer;
+};
+
static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar radius, SkScalar dir,
SkVector* newNormal) {
SkVector normal;
@@ -307,6 +358,63 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
+class SkSpotShadowTessellator {
+public:
+ SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate,
+ SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
+ bool transparent);
+
+ int vertexCount() const { return fPositions.count(); }
+ int indexCount() const { return fIndices.count(); }
+
+ UniqueArray<SkPoint> releasePositions() { return UniqueArray<SkPoint>(fPositions.release()); }
+ UniqueArray<SkColor> releaseColors() { return UniqueArray<SkColor>(fColors.release()); }
+ UniqueArray<uint16_t> releaseIndices() { return UniqueArray<uint16_t>(fIndices.release()); }
+
+private:
+ void computeClipBounds(const SkPath& path);
+
+ void handleLine(const SkPoint& p);
+ void handleLine(SkScalar scale, const SkVector& xlate, SkPoint p);
+
+ void handleQuad(const SkPoint pts[3]);
+ void handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]);
+
+ void handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]);
+
+ void handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w);
+
+ void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
+ void addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, SkScalar radiusSqd);
+ void addArc(const SkVector& nextNormal);
+ void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
+ void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
+
+ SkScalar fRadius;
+ SkColor fUmbraColor;
+ SkColor fPenumbraColor;
+
+ SkTDArray<SkPoint> fPositions;
+ SkTDArray<SkColor> fColors;
+ SkTDArray<uint16_t> fIndices;
+
+ int fPrevInnerIndex;
+ SkPoint fPrevPoint;
+ SkVector fPrevNormal;
+ int fFirstVertex;
+ SkPoint fFirstPoint;
+ SkVector fFirstNormal;
+ SkScalar fDirection;
+
+ SkPoint fCentroid;
+ SkTDArray<SkPoint> fClipPolygon;
+
+ // first three points
+ SkTDArray<SkPoint> fInitPoints;
+ // temporary buffer
+ SkTDArray<SkPoint> fPointBuffer;
+};
+
SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path,
SkScalar scale, const SkVector& translate,
SkScalar radius,
@@ -645,3 +753,30 @@
fPrevInnerIndex = fPositions.count() - 2;
fPrevNormal = nextNormal;
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkShadowVertices> SkShadowVertices::MakeAmbient(const SkPath& path, SkScalar radius,
+ SkColor umbraColor, SkColor penumbraColor,
+ bool transparent) {
+ SkAmbientShadowTessellator ambientTess(path, radius, umbraColor, penumbraColor, transparent);
+ int vcount = ambientTess.vertexCount();
+ int icount = ambientTess.indexCount();
+ return sk_sp<SkShadowVertices>(new SkShadowVertices(ambientTess.releasePositions(),
+ ambientTess.releaseColors(),
+ ambientTess.releaseIndices(), vcount,
+ icount));
+}
+
+sk_sp<SkShadowVertices> SkShadowVertices::MakeSpot(const SkPath& path, SkScalar scale,
+ const SkVector& translate, SkScalar radius,
+ SkColor umbraColor, SkColor penumbraColor,
+ bool transparent) {
+ SkSpotShadowTessellator spotTess(path, scale, translate, radius, umbraColor, penumbraColor,
+ transparent);
+ int vcount = spotTess.vertexCount();
+ int icount = spotTess.indexCount();
+ return sk_sp<SkShadowVertices>(new SkShadowVertices(spotTess.releasePositions(),
+ spotTess.releaseColors(),
+ spotTess.releaseIndices(), vcount, icount));
+}
diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h
index ababba7..301b684 100755
--- a/src/utils/SkShadowTessellator.h
+++ b/src/utils/SkShadowTessellator.h
@@ -9,6 +9,7 @@
#define SkShadowTessellator_DEFINED
#include "SkTDArray.h"
+#include "SkRefCnt.h"
#include "SkPoint.h"
#include "SkColor.h"
@@ -16,118 +17,53 @@
class SkMatrix;
class SkPath;
-// TODO: derive these two classes from a base class containing common elements
-
-/**
- * This class generates an ambient shadow 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.
- */
-class SkAmbientShadowTessellator {
+class SkShadowVertices : public SkRefCnt {
public:
- SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor,
- SkColor penumbraColor, bool transparent);
+ /**
+ * 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, SkScalar radius,
+ SkColor umbraColor, SkColor penumbraColor,
+ bool transparent);
- int vertexCount() { return fPositions.count(); }
- SkPoint* positions() { return fPositions.begin(); }
- SkColor* colors() { return fColors.begin(); }
- int indexCount() { return fIndices.count(); }
- uint16_t* indices() { return fIndices.begin(); }
+ /**
+ * 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, 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(); }
private:
- void handleLine(const SkPoint& p);
+ template<typename T> using Deleter = SkTDArray<SkPoint>::Deleter;
+ template<typename T> using UniqueArray = std::unique_ptr<const T[], Deleter<T>>;
- void handleQuad(const SkPoint pts[3]);
+ 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(indices) == SkToBool(indexCnt));
+ }
- void handleCubic(SkPoint pts[4]);
-
- void handleConic(SkPoint pts[3], SkScalar w);
-
- void addArc(const SkVector& nextNormal);
- void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
- void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
-
- SkScalar fRadius;
- SkColor fUmbraColor;
- SkColor fPenumbraColor;
- bool fTransparent;
-
- SkTDArray<SkPoint> fPositions;
- SkTDArray<SkColor> fColors;
- SkTDArray<uint16_t> fIndices;
-
- int fPrevInnerIndex;
- SkVector fPrevNormal;
- int fFirstVertex;
- SkVector fFirstNormal;
- SkScalar fDirection;
- int fCentroidCount;
-
- // first three points
- SkTDArray<SkPoint> fInitPoints;
- // temporary buffer
- SkTDArray<SkPoint> fPointBuffer;
-};
-
-/**
- * This class generates an spot shadow 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.
- */
-class SkSpotShadowTessellator {
-public:
- SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate,
- SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
- bool transparent);
-
- int vertexCount() { return fPositions.count(); }
- SkPoint* positions() { return fPositions.begin(); }
- SkColor* colors() { return fColors.begin(); }
- int indexCount() { return fIndices.count(); }
- uint16_t* indices() { return fIndices.begin(); }
-
-private:
- void computeClipBounds(const SkPath& path);
-
- void handleLine(const SkPoint& p);
- void handleLine(SkScalar scale, const SkVector& xlate, SkPoint p);
-
- void handleQuad(const SkPoint pts[3]);
- void handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]);
-
- void handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]);
-
- void handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w);
-
- void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
- void addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, SkScalar radiusSqd);
- void addArc(const SkVector& nextNormal);
- void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
- void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
-
- SkScalar fRadius;
- SkColor fUmbraColor;
- SkColor fPenumbraColor;
-
- SkTDArray<SkPoint> fPositions;
- SkTDArray<SkColor> fColors;
- SkTDArray<uint16_t> fIndices;
-
- int fPrevInnerIndex;
- SkPoint fPrevPoint;
- SkVector fPrevNormal;
- int fFirstVertex;
- SkPoint fFirstPoint;
- SkVector fFirstNormal;
- SkScalar fDirection;
-
- SkPoint fCentroid;
- SkTDArray<SkPoint> fClipPolygon;
-
- // first three points
- SkTDArray<SkPoint> fInitPoints;
- // temporary buffer
- SkTDArray<SkPoint> fPointBuffer;
+ int fVertexCnt;
+ int fIndexCnt;
+ UniqueArray<SkPoint> fPositions;
+ UniqueArray<SkColor> fColors;
+ UniqueArray<uint16_t> fIndices;
};
#endif
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index 5c92d66..6a08965 100755
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -87,6 +87,8 @@
canvas->save();
canvas->resetMatrix();
+ bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
+
if (ambientAlpha > 0) {
SkScalar radius = occluderHeight * kHeightFactor * kGeomFactor;
SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f)));
@@ -97,14 +99,15 @@
SkColor umbraColor = SkColorSetARGB(255, 0, ambientAlpha*255.9999f, umbraAlpha*255.9999f);
SkColor penumbraColor = SkColorSetARGB(255, 0, ambientAlpha*255.9999f, 0);
- SkAmbientShadowTessellator tess(xformedPath, radius, umbraColor, penumbraColor,
- SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag));
-
+ sk_sp<SkShadowVertices> vertices =
+ SkShadowVertices::MakeAmbient(xformedPath, radius, umbraColor, penumbraColor,
+ transparent);
SkPaint paint;
paint.setColor(color);
paint.setColorFilter(SkGaussianColorFilter::Make());
- canvas->drawVertices(SkCanvas::kTriangles_VertexMode, tess.vertexCount(), tess.positions(),
- nullptr, tess.colors(), tess.indices(), tess.indexCount(), paint);
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertices->vertexCount(),
+ vertices->positions(), nullptr, vertices->colors(),
+ vertices->indices(), vertices->indexCount(), paint);
}
if (spotAlpha > 0) {
@@ -120,15 +123,15 @@
SkColor umbraColor = SkColorSetARGB(255, 0, spotAlpha*255.9999f, 255);
SkColor penumbraColor = SkColorSetARGB(255, 0, spotAlpha*255.9999f, 0);
- SkSpotShadowTessellator tess(xformedPath, scale, spotOffset, radius,
- umbraColor, penumbraColor,
- SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag));
-
+ sk_sp<SkShadowVertices> vertices =
+ SkShadowVertices::MakeSpot(xformedPath, scale, spotOffset, radius, umbraColor,
+ penumbraColor, transparent);
SkPaint paint;
paint.setColor(color);
paint.setColorFilter(SkGaussianColorFilter::Make());
- canvas->drawVertices(SkCanvas::kTriangles_VertexMode, tess.vertexCount(), tess.positions(),
- nullptr, tess.colors(), tess.indices(), tess.indexCount(), paint);
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertices->vertexCount(),
+ vertices->positions(), nullptr, vertices->colors(),
+ vertices->indices(), vertices->indexCount(), paint);
}
canvas->restore();