diff --git a/include/core/SkPoint3.h b/include/core/SkPoint3.h index d4a2023082..41206f33b1 100644 --- a/include/core/SkPoint3.h +++ b/include/core/SkPoint3.h @@ -107,6 +107,24 @@ struct SK_API SkPoint3 { fZ -= v.fZ; } + /** Returns true if fX, fY, and fZ are measurable values. + + @return true for values other than infinities and NaN + */ + bool isFinite() const { + SkScalar accum = 0; + accum *= fX; + accum *= fY; + accum *= fZ; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + /** Returns the dot product of a and b, treating them as 3D vectors */ static SkScalar DotProduct(const SkPoint3& a, const SkPoint3& b) { diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index 11e8f2d5c6..57bf5851fa 100755 --- a/src/utils/SkShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -177,6 +177,12 @@ void SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) { void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) { #if SK_SUPPORT_GPU + // check for degeneracy + SkVector v0 = pts[1] - pts[0]; + SkVector v1 = pts[2] - pts[0]; + if (SkScalarNearlyZero(v0.cross(v1))) { + return; + } // TODO: Pull PathUtils out of Ganesh? int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); fPointBuffer.setReserve(maxCount); @@ -277,7 +283,7 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { }; } else { SkMatrix ctmInverse; - if (!ctm.invert(&ctmInverse)) { + if (!ctm.invert(&ctmInverse) || !ctmInverse.isFinite()) { return false; } // multiply by transpose diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index fcb3432450..b2f50ad40d 100644 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -535,6 +535,11 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi canvas->private_draw_shadow_rec(path, rec); } +static bool validate_rec(const SkDrawShadowRec& rec) { + return rec.fLightPos.isFinite() && rec.fZPlaneParams.isFinite() && + SkScalarIsFinite(rec.fLightRadius); +} + void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) { auto drawVertsProc = [this](const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint, SkScalar tx, SkScalar ty) { @@ -543,6 +548,10 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) { this->drawVertices(vertices, mode, paint); }; + if (!validate_rec(rec)) { + return; + } + SkMatrix viewMatrix = this->ctm(); SkAutoDeviceCTMRestore adr(this, SkMatrix::I());