Fix up shadows in raster.
authorJim Van Verth <jvanverth@google.com>
Mon, 1 May 2017 20:06:48 +0000 (16:06 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 2 May 2017 14:25:28 +0000 (14:25 +0000)
* Re-enable shadow blurs for raster circles and rrects
* Fix up the tessellation as much as possible to remove skinny triangles

Bug: skia:6425
Change-Id: I6548055084bc8596a052bcd3cec852766e084ba2
Reviewed-on: https://skia-review.googlesource.com/14943
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>

src/utils/SkShadowTessellator.cpp
src/utils/SkShadowUtils.cpp

index 5dee5df..36df514 100755 (executable)
@@ -54,7 +54,7 @@ protected:
 
     bool setTransformedHeightFunc(const SkMatrix& ctm);
 
-    void addArc(const SkVector& nextNormal, bool finishArc);
+    bool addArc(const SkVector& nextNormal, bool finishArc);
 
     SkShadowTessellator::HeightFunc         fHeightFunc;
     std::function<SkScalar(const SkPoint&)> fTransformedHeightFunc;
@@ -105,17 +105,17 @@ static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir,
 
 static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScalar r,
                                  SkScalar* rotSin, SkScalar* rotCos, int* n) {
-    const SkScalar kRecipPixelsPerArcSegment = 0.25f;
+    const SkScalar kRecipPixelsPerArcSegment = 0.125f;
 
     SkScalar rCos = v1.dot(v2);
     SkScalar rSin = v1.cross(v2);
     SkScalar theta = SkScalarATan2(rSin, rCos);
 
-    SkScalar steps = r*theta*kRecipPixelsPerArcSegment;
+    int steps = SkScalarFloorToInt(r*theta*kRecipPixelsPerArcSegment);
 
     SkScalar dTheta = theta / steps;
     *rotSin = SkScalarSinCos(dTheta, rotCos);
-    *n = SkScalarFloorToInt(steps);
+    *n = steps;
 }
 
 SkBaseShadowTessellator::SkBaseShadowTessellator(SkShadowTessellator::HeightFunc heightFunc,
@@ -234,32 +234,34 @@ void SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkS
     }
 }
 
-void SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) {
+bool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) {
     // fill in fan from previous quad
     SkScalar rotSin, rotCos;
     int numSteps;
     compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps);
     SkVector prevNormal = fPrevNormal;
-    for (int i = 0; i < numSteps; ++i) {
+    for (int i = 0; i < numSteps-1; ++i) {
         SkVector currNormal;
         currNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
         currNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
         *fPositions.push() = fPrevPoint + currNormal;
         *fColors.push() = fPenumbraColor;
         *fIndices.push() = fPrevUmbraIndex;
-        *fIndices.push() = fPositions.count() - 2;
         *fIndices.push() = fPositions.count() - 1;
+        *fIndices.push() = fPositions.count() - 2;
 
         prevNormal = currNormal;
     }
-    if (finishArc) {
+    if (finishArc && numSteps) {
         *fPositions.push() = fPrevPoint + nextNormal;
         *fColors.push() = fPenumbraColor;
         *fIndices.push() = fPrevUmbraIndex;
-        *fIndices.push() = fPositions.count() - 2;
         *fIndices.push() = fPositions.count() - 1;
+        *fIndices.push() = fPositions.count() - 2;
     }
     fPrevNormal = nextNormal;
+
+    return (numSteps > 0);
 }
 
 bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) {
@@ -488,11 +490,15 @@ SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
         fPrevUmbraIndex = fFirstVertex;
         fPrevPoint = fFirstPoint;
         fRadius = this->offset(fTransformedHeightFunc(fPrevPoint));
-        this->addArc(fFirstNormal, false);
-
-        *fIndices.push() = fFirstVertex;
-        *fIndices.push() = fPositions.count() - 1;
-        *fIndices.push() = fFirstVertex + 1;
+        if (this->addArc(fFirstNormal, false)) {
+            *fIndices.push() = fFirstVertex;
+            *fIndices.push() = fPositions.count() - 1;
+            *fIndices.push() = fFirstVertex + 1;
+        } else {
+            // arc is too small, set the first penumbra point to be the same position
+            // as the last one
+            fPositions[fFirstVertex + 1] = fPositions[fPositions.count() - 1];
+        }
     }
     fSucceeded = true;
 }
@@ -858,14 +864,21 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMat
     if (fPositions.count() >= 3) {
         fPrevUmbraIndex = fFirstVertex;
         fPrevPoint = fFirstPoint;
-        this->addArc(fFirstNormal, false);
-
-        *fIndices.push() = fFirstVertex;
-        *fIndices.push() = fPositions.count() - 1;
-        if (fFirstUmbraOutside) {
-            *fIndices.push() = fFirstVertex + 2;
+        if (this->addArc(fFirstNormal, false)) {
+            *fIndices.push() = fFirstVertex;
+            *fIndices.push() = fPositions.count() - 1;
+            if (fFirstUmbraOutside) {
+                *fIndices.push() = fFirstVertex + 2;
+            } else {
+                *fIndices.push() = fFirstVertex + 1;
+            }
         } else {
-            *fIndices.push() = fFirstVertex + 1;
+            // no arc added, fix up by setting first penumbra point position to last one
+            if (fFirstUmbraOutside) {
+                fPositions[fFirstVertex + 2] = fPositions[fPositions.count() - 1];
+            } else {
+                fPositions[fFirstVertex + 1] = fPositions[fPositions.count() - 1];
+            }
         }
     }
 
@@ -1160,9 +1173,10 @@ void SkSpotShadowTessellator::handlePolyPoint(const SkPoint& p) {
         fFirstVertex = fPositions.count();
         fPrevNormal = fFirstNormal;
         fPrevPoint = fFirstPoint;
-        fPrevUmbraIndex = fFirstVertex;
+        fPrevUmbraIndex = -1;
 
         this->addInnerPoint(fFirstPoint);
+        fPrevUmbraIndex = fFirstVertex;
 
         if (!fTransparent) {
             SkPoint clipPoint;
@@ -1205,7 +1219,7 @@ bool SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint) {
     fPrevPoint = pathPoint;
 
     // merge "close" points
-    if (fPrevUmbraIndex == fFirstVertex ||
+    if (fPrevUmbraIndex == -1 ||
         !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) {
         *fPositions.push() = umbraPoint;
         *fColors.push() = fUmbraColor;
index fc0d44a..928eb66 100644 (file)
@@ -458,6 +458,11 @@ static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar
                                   const SkPoint3& devLightPos, SkScalar lightRadius,
                                   SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
                                   uint32_t flags) {
+    // only supported in GPU code
+    if (!canvas->getGrContext()) {
+        return false;
+    }
+
     SkRect rect;
     SkRRect rrect;
     if (canvas->getTotalMatrix().isSimilarity()) {