Change shadow tessellators to use SkColor and move to util.
authorJim Van Verth <jvanverth@google.com>
Mon, 30 Jan 2017 18:11:45 +0000 (13:11 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Mon, 30 Jan 2017 18:44:38 +0000 (18:44 +0000)
BUG=skia:6119

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

gn/gpu.gni
gn/utils.gni
include/gpu/effects/GrBlurredEdgeFragmentProcessor.h
src/effects/shadows/SkAmbientShadowMaskFilter.cpp
src/effects/shadows/SkSpotShadowMaskFilter.cpp
src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
src/utils/SkShadowTessellator.cpp [moved from src/gpu/effects/GrShadowTessellator.cpp with 91% similarity]
src/utils/SkShadowTessellator.h [moved from src/gpu/effects/GrShadowTessellator.h with 81% similarity]
src/utils/SkShadowUtils.cpp

index b3ed694..001e6c1 100644 (file)
@@ -329,8 +329,6 @@ skia_gpu_sources = [
   "$_src/gpu/effects/GrRRectEffect.h",
   "$_src/gpu/effects/GrShadowGeoProc.cpp",
   "$_src/gpu/effects/GrShadowGeoProc.h",
-  "$_src/gpu/effects/GrShadowTessellator.cpp",
-  "$_src/gpu/effects/GrShadowTessellator.h",
   "$_src/gpu/effects/GrSimpleTextureEffect.cpp",
   "$_src/gpu/effects/GrSimpleTextureEffect.h",
   "$_src/gpu/effects/GrSingleTextureEffect.cpp",
index 068881f..8d3f1c7 100644 (file)
@@ -69,6 +69,8 @@ skia_utils_sources = [
   "$_src/utils/SkRGBAToYUV.h",
   "$_src/utils/SkShadowPaintFilterCanvas.cpp",
   "$_src/utils/SkShadowPaintFilterCanvas.h",
+  "$_src/utils/SkShadowTessellator.cpp",
+  "$_src/utils/SkShadowTessellator.h",
   "$_src/utils/SkShadowUtils.cpp",
   "$_src/utils/SkTextBox.cpp",
   "$_src/utils/SkTextureCompressor.cpp",
index 2e52485..c9dd276 100755 (executable)
  * If the primitive supports an implicit distance to the edge, the radius of the blur is specified
  * by r & g values of the color in 14.2 fixed point. For spot shadows, we increase the stroke width
  * to set the shadow against the shape. This pad is specified by b, also in 6.2 fixed point.
+ * The a value represents the max final alpha.
  *
  * When not using implicit distance, then b in the input color represents the input to the
- * blur function.
+ * blur function, and r the max final alpha.
  *
- * In either case, the a value represents the max final alpha.
  */
 class GrBlurredEdgeFP : public GrFragmentProcessor {
 public:
index 0672020..9db75c5 100755 (executable)
@@ -17,8 +17,6 @@
 #include "GrStyle.h"
 #include "GrTexture.h"
 #include "GrTextureProxy.h"
-#include "effects/GrBlurredEdgeFragmentProcessor.h"
-#include "effects/GrShadowTessellator.h"
 #include "SkStrokeRec.h"
 #endif
 
@@ -164,41 +162,21 @@ bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texPr
         return false;
     }
 
-#ifdef SUPPORT_FAST_PATH
     // if circle
     // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
     // have our own GeometryProc.
     if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) {
         SkRRect rrect = SkRRect::MakeOval(path.getBounds());
-        return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
+        return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip,
                                               SkMatrix::I(), strokeRec, rrect, rrect);
     } else if (path.isRect(nullptr)) {
         SkRRect rrect = SkRRect::MakeRect(path.getBounds());
-        return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
+        return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip,
                                               SkMatrix::I(), strokeRec, rrect, rrect);
     }
-#endif
-
-    SkScalar radius = fOccluderHeight * kHeightFactor * kGeomFactor;
-    SkScalar umbraAlpha = SkScalarInvert((1.0f+SkTMax(fOccluderHeight * kHeightFactor, 0.0f)));
-    // umbraColor is the interior value, penumbraColor the exterior value.
-    // umbraAlpha is the factor that is linearly interpolated from outside to inside, and
-    // then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get
-    // the final alpha.
-    GrColor  umbraColor = GrColorPackRGBA(0, 0, umbraAlpha*255.9999f, fAmbientAlpha*255.9999f);
-    GrColor  penumbraColor = GrColorPackRGBA(0, 0, 0, fAmbientAlpha*255.9999f);
-
-    GrAmbientShadowTessellator tess(path, radius, umbraColor, penumbraColor,
-                                SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag));
 
-    sk_sp<GrFragmentProcessor> edgeFP = GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
-    paint.addColorFragmentProcessor(std::move(edgeFP));
-
-    rtContext->drawVertices(clip, std::move(paint), SkMatrix::I(), kTriangles_GrPrimitiveType,
-                            tess.vertexCount(), tess.positions(), nullptr,
-                            tess.colors(), tess.indices(), tess.indexCount());
-
-    return true;
+    // TODO
+    return false;
 }
 
 bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
@@ -209,10 +187,6 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
                                                              const SkStrokeRec& strokeRec,
                                                              const SkRRect& rrect,
                                                              const SkRRect& devRRect) const {
-#ifndef SUPPORT_FAST_PATH
-    return false;
-#endif
-
     // It's likely the caller has already done these checks, but we have to be sure.
     // TODO: support analytic blurring of general rrect
 
@@ -246,7 +220,7 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
     if (fAmbientAlpha > 0.0f) {
         SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor;
         const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f));
-        const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
+        const SkScalar ambientOffset = srcSpaceAmbientRadius / umbraAlpha;
 
         // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius
         // to get our stroke shape.
index 7a1f311..99a03db 100755 (executable)
@@ -17,8 +17,6 @@
 #include "GrStyle.h"
 #include "GrTexture.h"
 #include "GrTextureProxy.h"
-#include "effects/GrBlurredEdgeFragmentProcessor.h"
-#include "effects/GrShadowTessellator.h"
 #include "SkStrokeRec.h"
 #endif
 
@@ -181,45 +179,20 @@ bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvi
         return false;
     }
 
-#ifdef SUPPORT_FAST_PATH
     // if circle
     // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
     // have our own GeometryProc.
     if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) {
         SkRRect rrect = SkRRect::MakeOval(path.getBounds());
-        return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
+        return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip,
                                               SkMatrix::I(), strokeRec, rrect, rrect);
     } else if (path.isRect(nullptr)) {
         SkRRect rrect = SkRRect::MakeRect(path.getBounds());
-        return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
+        return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip,
                                               SkMatrix::I(), strokeRec, rrect, rrect);
     }
-#endif
-
-    float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f);
-
-    SkScalar radius = fLightRadius * zRatio;
-
-    // Compute the scale and translation for the spot shadow.
-    const SkScalar scale = fLightPos.fZ / (fLightPos.fZ - fOccluderHeight);
-
-    SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
-    const SkVector spotOffset = SkVector::Make(zRatio*(center.fX - fLightPos.fX),
-                                               zRatio*(center.fY - fLightPos.fY));
-
-    GrColor  umbraColor = GrColorPackRGBA(0, 0, 255, fSpotAlpha*255.9999f);
-    GrColor  penumbraColor = GrColorPackRGBA(0, 0, 0, fSpotAlpha*255.9999f);
-    GrSpotShadowTessellator tess(path, scale, spotOffset, radius, umbraColor, penumbraColor,
-                                SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag));
-
-    sk_sp<GrFragmentProcessor> edgeFP = GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
-    paint.addColorFragmentProcessor(std::move(edgeFP));
 
-    rtContext->drawVertices(clip, std::move(paint), SkMatrix::I(), kTriangles_GrPrimitiveType,
-                            tess.vertexCount(), tess.positions(), nullptr,
-                            tess.colors(), tess.indices(), tess.indexCount());
-
-    return true;
+    return false;
 }
 
 bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
@@ -230,10 +203,6 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
                                                           const SkStrokeRec& strokeRec,
                                                           const SkRRect& rrect,
                                                           const SkRRect& devRRect) const {
-#ifndef SUPPORT_FAST_PATH
-    return false;
-#endif
-
     // It's likely the caller has already done these checks, but we have to be sure.
     // TODO: support analytic blurring of general rrect
 
index 1441a75..502b6e5 100755 (executable)
@@ -41,8 +41,13 @@ public:
                 fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);");
                 break;
         }
-        fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);",
-                                 args.fOutputColor);
+        if (!args.fGpImplementsDistanceVector) {
+            fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.g);",
+                                     args.fOutputColor);
+        } else {
+            fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);",
+                                     args.fOutputColor);
+        }
     }
 
 protected:
similarity index 91%
rename from src/gpu/effects/GrShadowTessellator.cpp
rename to src/utils/SkShadowTessellator.cpp
index a51a66a..5ad5e4f 100755 (executable)
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "GrShadowTessellator.h"
+#include "SkShadowTessellator.h"
 #include "GrPathUtils.h"
 
 #include "SkGeometry.h"
@@ -39,10 +39,10 @@ static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScala
     *n = SkScalarFloorToInt(steps);
 }
 
-GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkPath& path,
+SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
                                                        SkScalar radius,
-                                                       GrColor umbraColor,
-                                                       GrColor penumbraColor,
+                                                       SkColor umbraColor,
+                                                       SkColor penumbraColor,
                                                        bool transparent)
     : fRadius(radius)
     , fUmbraColor(umbraColor)
@@ -142,7 +142,7 @@ static const SkScalar kQuadTolerance = 0.2f;
 static const SkScalar kCubicTolerance = 0.2f;
 static const SkScalar kConicTolerance = 0.5f;
 
-void GrAmbientShadowTessellator::handleLine(const SkPoint& p)  {
+void SkAmbientShadowTessellator::handleLine(const SkPoint& p)  {
     if (fInitPoints.count() < 2) {
         *fInitPoints.push() = p;
         return;
@@ -195,7 +195,9 @@ void GrAmbientShadowTessellator::handleLine(const SkPoint& p)  {
     }
 }
 
-void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
+void SkAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
+#if SK_SUPPORT_GPU
+    // TODO: Pull PathUtils out of Ganesh?
     int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
     fPointBuffer.setReserve(maxCount);
     SkPoint* target = fPointBuffer.begin();
@@ -205,9 +207,12 @@ void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
     for (int i = 0; i < count; i++) {
         this->handleLine(fPointBuffer[i]);
     }
+#endif
 }
 
-void GrAmbientShadowTessellator::handleCubic(SkPoint pts[4]) {
+void SkAmbientShadowTessellator::handleCubic(SkPoint pts[4]) {
+#if SK_SUPPORT_GPU
+    // TODO: Pull PathUtils out of Ganesh?
     int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
     fPointBuffer.setReserve(maxCount);
     SkPoint* target = fPointBuffer.begin();
@@ -217,9 +222,10 @@ void GrAmbientShadowTessellator::handleCubic(SkPoint pts[4]) {
     for (int i = 0; i < count; i++) {
         this->handleLine(fPointBuffer[i]);
     }
+#endif
 }
 
-void GrAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) {
+void SkAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) {
     SkAutoConicToQuads quadder;
     const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
     SkPoint lastPoint = *(quads++);
@@ -235,7 +241,7 @@ void GrAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) {
     }
 }
 
-void GrAmbientShadowTessellator::addArc(const SkVector& nextNormal) {
+void SkAmbientShadowTessellator::addArc(const SkVector& nextNormal) {
     // fill in fan from previous quad
     SkScalar rotSin, rotCos;
     int numSteps;
@@ -255,7 +261,7 @@ void GrAmbientShadowTessellator::addArc(const SkVector& nextNormal) {
     }
 }
 
-void GrAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
+void SkAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
                                                      const SkVector& nextNormal) {
     // close out previous arc
     *fPositions.push() = fPositions[fPrevInnerIndex] + nextNormal;
@@ -267,7 +273,7 @@ void GrAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
     this->addEdge(nextPoint, nextNormal);
 }
 
-void GrAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
+void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
     // add next quad
     *fPositions.push() = nextPoint;
     *fColors.push() = fUmbraColor;
@@ -298,10 +304,10 @@ void GrAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-GrSpotShadowTessellator::GrSpotShadowTessellator(const SkPath& path,
+SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path,
                                                  SkScalar scale, const SkVector& translate,
                                                  SkScalar radius,
-                                                 GrColor umbraColor, GrColor penumbraColor,
+                                                 SkColor umbraColor, SkColor penumbraColor,
                                                  bool /* transparent */)
     : fRadius(radius)
     , fUmbraColor(umbraColor)
@@ -394,7 +400,7 @@ GrSpotShadowTessellator::GrSpotShadowTessellator(const SkPath& path,
     }
 }
 
-void GrSpotShadowTessellator::computeClipBounds(const SkPath& path) {
+void SkSpotShadowTessellator::computeClipBounds(const SkPath& path) {
     // walk around the path and compute clip polygon
     // if original path is transparent, will accumulate sum of points for centroid
     SkPath::Iter iter(path, true);
@@ -443,7 +449,7 @@ void GrSpotShadowTessellator::computeClipBounds(const SkPath& path) {
     fCentroid *= SkScalarInvert(centroidCount);
 }
 
-void GrSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
+void SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
                                         SkPoint* pts, int count) {
     // TODO: vectorize
     for (int i = 0; i < count; ++i) {
@@ -452,7 +458,7 @@ void GrSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
     }
 }
 
-void GrSpotShadowTessellator::handleLine(const SkPoint& p) {
+void SkSpotShadowTessellator::handleLine(const SkPoint& p) {
     if (fInitPoints.count() < 2) {
         *fInitPoints.push() = p;
         return;
@@ -503,12 +509,14 @@ void GrSpotShadowTessellator::handleLine(const SkPoint& p) {
     }
 }
 
-void GrSpotShadowTessellator::handleLine(SkScalar scale, const SkVector& xlate, SkPoint p) {
+void SkSpotShadowTessellator::handleLine(SkScalar scale, const SkVector& xlate, SkPoint p) {
     this->mapPoints(scale, xlate, &p, 1);
     this->handleLine(p);
 }
 
-void GrSpotShadowTessellator::handleQuad(const SkPoint pts[3]) {
+void SkSpotShadowTessellator::handleQuad(const SkPoint pts[3]) {
+#if SK_SUPPORT_GPU
+    // TODO: Pull PathUtils out of Ganesh?
     int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
     fPointBuffer.setReserve(maxCount);
     SkPoint* target = fPointBuffer.begin();
@@ -518,14 +526,17 @@ void GrSpotShadowTessellator::handleQuad(const SkPoint pts[3]) {
     for (int i = 0; i < count; i++) {
         this->handleLine(fPointBuffer[i]);
     }
+#endif
 }
 
-void GrSpotShadowTessellator::handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]) {
+void SkSpotShadowTessellator::handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]) {
     this->mapPoints(scale, xlate, pts, 3);
     this->handleQuad(pts);
 }
 
-void GrSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]) {
+void SkSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]) {
+#if SK_SUPPORT_GPU
+    // TODO: Pull PathUtils out of Ganesh?
     this->mapPoints(scale, xlate, pts, 4);
     int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
     fPointBuffer.setReserve(maxCount);
@@ -536,9 +547,10 @@ void GrSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate,
     for (int i = 0; i < count; i++) {
         this->handleLine(fPointBuffer[i]);
     }
+#endif
 }
 
-void GrSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate,
+void SkSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate,
                                           SkPoint pts[3], SkScalar w) {
     this->mapPoints(scale, xlate, pts, 3);
     SkAutoConicToQuads quadder;
@@ -556,7 +568,7 @@ void GrSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate,
     }
 }
 
-void GrSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, GrColor umbraColor,
+void SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
                                             SkScalar radius) {
     SkVector v = fCentroid - pathPoint;
     SkScalar distance = v.length();
@@ -574,7 +586,7 @@ void GrSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, GrColor um
     fPrevPoint = pathPoint;
 }
 
-void GrSpotShadowTessellator::addArc(const SkVector& nextNormal) {
+void SkSpotShadowTessellator::addArc(const SkVector& nextNormal) {
     // fill in fan from previous quad
     SkScalar rotSin, rotCos;
     int numSteps;
@@ -594,7 +606,7 @@ void GrSpotShadowTessellator::addArc(const SkVector& nextNormal) {
     }
 }
 
-void GrSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
+void SkSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
                                                   const SkVector& nextNormal) {
     // close out previous arc
     SkPoint newPoint = fPrevPoint + nextNormal;
@@ -607,7 +619,7 @@ void GrSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
     this->addEdge(nextPoint, nextNormal);
 }
 
-void GrSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
+void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
     // add next quad
     this->addInnerPoint(nextPoint, fUmbraColor, fRadius);
     SkPoint newPoint = nextPoint + nextNormal;
similarity index 81%
rename from src/gpu/effects/GrShadowTessellator.h
rename to src/utils/SkShadowTessellator.h
index c2acde7..ababba7 100755 (executable)
@@ -5,13 +5,13 @@
  * found in the LICENSE file.
  */
 
-#ifndef GrShadowTessellator_DEFINED
-#define GrShadowTessellator_DEFINED
+#ifndef SkShadowTessellator_DEFINED
+#define SkShadowTessellator_DEFINED
 
 #include "SkTDArray.h"
 #include "SkPoint.h"
 
-#include "GrColor.h"
+#include "SkColor.h"
 
 class SkMatrix;
 class SkPath;
@@ -23,14 +23,14 @@ class SkPath;
  * 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 GrAmbientShadowTessellator {
+class SkAmbientShadowTessellator {
 public:
-    GrAmbientShadowTessellator(const SkPath& path, SkScalar radius, GrColor umbraColor,
-                               GrColor penumbraColor, bool transparent);
+    SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor,
+                               SkColor penumbraColor, bool transparent);
 
     int      vertexCount() { return fPositions.count(); }
     SkPoint* positions() { return fPositions.begin(); }
-    GrColor* colors() { return fColors.begin(); }
+    SkColor* colors() { return fColors.begin(); }
     int      indexCount() { return fIndices.count(); }
     uint16_t* indices() { return fIndices.begin(); }
 
@@ -48,12 +48,12 @@ private:
     void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
 
     SkScalar            fRadius;
-    GrColor             fUmbraColor;
-    GrColor             fPenumbraColor;
+    SkColor             fUmbraColor;
+    SkColor             fPenumbraColor;
     bool                fTransparent;
 
     SkTDArray<SkPoint>  fPositions;
-    SkTDArray<GrColor>  fColors;
+    SkTDArray<SkColor>  fColors;
     SkTDArray<uint16_t> fIndices;
 
     int                 fPrevInnerIndex;
@@ -74,15 +74,15 @@ private:
  * 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 GrSpotShadowTessellator {
+class SkSpotShadowTessellator {
 public:
-    GrSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate,
-                            SkScalar radius, GrColor umbraColor, GrColor penumbraColor,
+    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(); }
-    GrColor* colors() { return fColors.begin(); }
+    SkColor* colors() { return fColors.begin(); }
     int      indexCount() { return fIndices.count(); }
     uint16_t* indices() { return fIndices.begin(); }
 
@@ -100,17 +100,17 @@ private:
     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, GrColor umbraColor, SkScalar radiusSqd);
+    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;
-    GrColor             fUmbraColor;
-    GrColor             fPenumbraColor;
+    SkColor             fUmbraColor;
+    SkColor             fPenumbraColor;
 
     SkTDArray<SkPoint>  fPositions;
-    SkTDArray<GrColor>  fColors;
+    SkTDArray<SkColor>  fColors;
     SkTDArray<uint16_t> fIndices;
 
     int                 fPrevInnerIndex;
index e93f778..5c92d66 100755 (executable)
 
 #include "SkShadowUtils.h"
 #include "SkCanvas.h"
-#include "../effects/shadows/SkAmbientShadowMaskFilter.h"
-#include "../effects/shadows/SkSpotShadowMaskFilter.h"
+#include "SkColorFilter.h"
+#include "SkPath.h"
+#include "SkShadowTessellator.h"
+
+/**
+*  Gaussian color filter -- produces a Gaussian ramp based on the color's B value,
+*                           then blends with the color's G value.
+*                           Final result is black with alpha of Gaussian(B)*G.
+*                           The assumption is that the original color's alpha is 1.
+*/
+class SK_API SkGaussianColorFilter : public SkColorFilter {
+public:
+    static sk_sp<SkColorFilter> Make() {
+        return sk_sp<SkColorFilter>(new SkGaussianColorFilter);
+    }
+
+    void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
+
+#if SK_SUPPORT_GPU
+    sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
+#endif
+
+    SK_TO_STRING_OVERRIDE()
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkGaussianColorFilter)
+
+protected:
+    void flatten(SkWriteBuffer&) const override {}
+
+private:
+    SkGaussianColorFilter() : INHERITED() {}
+
+    typedef SkColorFilter INHERITED;
+};
+
+void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
+    for (int i = 0; i < count; ++i) {
+        SkPMColor c = src[i];
+
+        SkScalar factor = SK_Scalar1 - SkGetPackedB32(c) / 255.f;
+        factor = SkScalarExp(-factor * factor * 4) - 0.018f;
+
+        dst[i] = SkPackARGB32(factor*SkGetPackedG32(c), 0, 0, 0);
+    }
+}
+
+sk_sp<SkFlattenable> SkGaussianColorFilter::CreateProc(SkReadBuffer&) {
+    return Make();
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void SkGaussianColorFilter::toString(SkString* str) const {
+    str->append("SkGaussianColorFilter ");
+}
+#endif
+
+#if SK_SUPPORT_GPU
+#include "effects/GrBlurredEdgeFragmentProcessor.h"
+
+sk_sp<GrFragmentProcessor> SkGaussianColorFilter::asFragmentProcessor(GrContext*,
+                                                                      SkColorSpace*) const {
+    return GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+static const float kHeightFactor = 1.0f / 128.0f;
+static const float kGeomFactor = 64.0f;
 
 // Draw an offset spot shadow and outlining ambient shadow for the given path.
 void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
                                const SkPoint3& lightPos, SkScalar lightRadius,
                                SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
                                uint32_t flags) {
-    SkPaint newPaint;
-    newPaint.setColor(color);
-    newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, flags));
-    canvas->drawPath(path, newPaint);
-    newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
-                                                        spotAlpha, flags));
-    canvas->drawPath(path, newPaint);
+
+    SkPath xformedPath;
+    // TODO: handle transforming the path as part of the tessellator
+    path.transform(canvas->getTotalMatrix(), &xformedPath);
+    canvas->save();
+    canvas->resetMatrix();
+
+    if (ambientAlpha > 0) {
+        SkScalar radius = occluderHeight * kHeightFactor * kGeomFactor;
+        SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f)));
+        // umbraColor is the interior value, penumbraColor the exterior value.
+        // umbraAlpha is the factor that is linearly interpolated from outside to inside, and
+        // then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get
+        // the final alpha.
+        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));
+
+        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);
+    }
+
+    if (spotAlpha > 0) {
+        float zRatio = SkTPin(occluderHeight / (lightPos.fZ - occluderHeight), 0.0f, 0.95f);
+        SkScalar radius = lightRadius * zRatio;
+
+        // Compute the scale and translation for the spot shadow.
+        const SkScalar scale = lightPos.fZ / (lightPos.fZ - occluderHeight);
+
+        SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
+        const SkVector spotOffset = SkVector::Make(zRatio*(center.fX - lightPos.fX),
+                                                   zRatio*(center.fY - lightPos.fY));
+
+        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));
+
+        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->restore();
 }