From 0dda9cb881900241c1c2193ddf3bede72cda898b Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Fri, 3 Feb 2017 10:33:25 -0500 Subject: Make shadow tessellators fail gracefully and add unit test for this. Change-Id: I42a9d06a18928588347a6dea2f6150518ba29aa8 Reviewed-on: https://skia-review.googlesource.com/7886 Commit-Queue: Brian Salomon Reviewed-by: Jim Van Verth --- src/utils/SkShadowTessellator.cpp | 55 ++++++++++++++++++++++++++++----------- src/utils/SkShadowTessellator.h | 3 ++- src/utils/SkShadowUtils.cpp | 3 +++ 3 files changed, 45 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index f140ceb2b1..a0a011f171 100755 --- a/src/utils/SkShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -26,6 +26,8 @@ public: 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 releasePositions() { @@ -71,6 +73,8 @@ private: SkTDArray fInitPoints; // temporary buffer SkTDArray fPointBuffer; + + bool fSucceeded; }; static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar radius, SkScalar dir, @@ -107,12 +111,12 @@ SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, SkColor umbraColor, SkColor penumbraColor, bool transparent) - : fRadius(radius) - , fUmbraColor(umbraColor) - , fPenumbraColor(penumbraColor) - , fTransparent(transparent) - , fPrevUmbraIndex(-1) { - + : fRadius(radius) + , fUmbraColor(umbraColor) + , fPenumbraColor(penumbraColor) + , fTransparent(transparent) + , fPrevUmbraIndex(-1) + , fSucceeded(false) { // Outer ring: 3*numPts // Middle ring: numPts fPositions.setReserve(4 * path.countPoints()); @@ -154,6 +158,10 @@ SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, } } + if (!this->indexCount()) { + return; + } + SkVector normal; if (compute_normal(fPositions[fPrevUmbraIndex], fPositions[fFirstVertex], fRadius, fDirection, &normal)) { @@ -198,6 +206,7 @@ SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, *fIndices.push() = fPositions.count() - 1; *fIndices.push() = fFirstVertex + 1; } + fSucceeded = true; } // tesselation tolerance values, in device space pixels @@ -388,6 +397,8 @@ public: return UniqueArray(static_cast(fIndices.release())); } + bool succeeded() const { return fSucceeded; } + private: void computeClipBounds(const SkPath& path); void checkUmbraAndTransformCentroid(SkScalar scale, const SkVector& xlate, @@ -439,6 +450,8 @@ private: SkTDArray fInitPoints; // temporary buffer SkTDArray fPointBuffer; + + bool fSucceeded; }; @@ -448,15 +461,16 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor, SkColor penumbraColor, bool transparent) - : fRadius(radius) - , fUmbraColor(umbraColor) - , fPenumbraColor(penumbraColor) - , fTransparent(transparent) - , fValidUmbra(true) - , fPrevUmbraIndex(-1) - , fCurrPolyPoint(0) - , fPrevUmbraOutside(false) - , fFirstUmbraOutside(false) { + : fRadius(radius) + , fUmbraColor(umbraColor) + , fPenumbraColor(penumbraColor) + , fTransparent(transparent) + , fValidUmbra(true) + , fPrevUmbraIndex(-1) + , fCurrPolyPoint(0) + , fPrevUmbraOutside(false) + , fFirstUmbraOutside(false) + , fSucceeded(false) { // TODO: calculate these better // Penumbra ring: 3*numPts @@ -514,6 +528,10 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, } } + if (!this->indexCount()) { + return; + } + SkVector normal; if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection, &normal)) { @@ -579,6 +597,7 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, *fIndices.push() = fFirstVertex + 1; } } + fSucceeded = true; } void SkSpotShadowTessellator::computeClipBounds(const SkPath& path) { @@ -1008,6 +1027,9 @@ sk_sp SkShadowVertices::MakeAmbient(const SkPath& path, SkScal SkColor umbraColor, SkColor penumbraColor, bool transparent) { SkAmbientShadowTessellator ambientTess(path, radius, umbraColor, penumbraColor, transparent); + if (!ambientTess.succeeded()) { + return nullptr; + } int vcount = ambientTess.vertexCount(); int icount = ambientTess.indexCount(); return sk_sp(new SkShadowVertices(ambientTess.releasePositions(), @@ -1022,6 +1044,9 @@ sk_sp SkShadowVertices::MakeSpot(const SkPath& path, SkScalar bool transparent) { SkSpotShadowTessellator spotTess(path, scale, translate, radius, umbraColor, penumbraColor, transparent); + if (!spotTess.succeeded()) { + return nullptr; + } int vcount = spotTess.vertexCount(); int icount = spotTess.indexCount(); return sk_sp(new SkShadowVertices(spotTess.releasePositions(), diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h index 13924f204f..c9abd72a29 100755 --- a/src/utils/SkShadowTessellator.h +++ b/src/utils/SkShadowTessellator.h @@ -61,7 +61,8 @@ private: , fPositions(std::move(positions)) , fColors(std::move(colors)) , fIndices(std::move(indices)) { - SkASSERT(SkToBool(fIndices) == SkToBool(indexCnt)); + SkASSERT(SkToBool(fPositions) && SkToBool(fColors) && SkToBool(vertexCnt) && + SkToBool(fIndices) && SkToBool(indexCnt)); } int fVertexCnt; diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index 32f1c6f165..83699c5625 100755 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -267,6 +267,9 @@ void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, S } else { // TODO: handle transforming the path as part of the tessellator vertices = factory.makeVertices(path.transformedPath()); + if (!vertices) { + return; + } translate = &kZeroTranslate; } -- cgit v1.2.3