Combine the ambient and spot alphas into the base color
authorJim Van Verth <jvanverth@google.com>
Thu, 4 May 2017 13:58:17 +0000 (09:58 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Thu, 4 May 2017 14:28:28 +0000 (14:28 +0000)
for geometric shadows.

This matches the analytic shadow approach better, and
is color space invariant.
Also includes cleanup in SampleAndroidShadows.

Bug: skia:6546
Change-Id: I7a7cd060420dae741f967334c8b19542a14f0bcf
Reviewed-on: https://skia-review.googlesource.com/15228
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
include/private/SkShadowFlags.h
samplecode/SampleAndroidShadows.cpp
src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
src/utils/SkShadowTessellator.cpp
src/utils/SkShadowTessellator.h
src/utils/SkShadowUtils.cpp
tests/ShadowUtilsTest.cpp

index 23b0f54..8caf632 100644 (file)
@@ -14,8 +14,10 @@ enum SkShadowFlags {
     /** The occluding object is not opaque. Knowing that the occluder is opaque allows
     * us to cull shadow geometry behind it and improve performance. */
     kTransparentOccluder_ShadowFlag = 0x01,
+    /** Don't try to use analytic shadows. */
+    kGeometricOnly_ShadowFlag = 0x02,
     /** mask for all shadow flags */
-    kAll_ShadowFlag = 0x01
+    kAll_ShadowFlag = 0x03
 };
 
 #endif
index 02b494f..99e5ff4 100644 (file)
@@ -21,8 +21,6 @@
 #include "SkView.h"
 #include "sk_tool_utils.h"
 
-#define USE_SHADOW_UTILS
-
 ////////////////////////////////////////////////////////////////////////////
 
 class ShadowsView : public SampleView {
@@ -129,327 +127,27 @@ protected:
         canvas->drawColor(0xFFDDDDDD);
     }
 
-    static void GetOcclRect(const SkPath& path, SkRect* occlRect) {
-        SkRect pathRect;
-        SkRRect pathRRect;
-        if (path.isOval(&pathRect)) {
-            *occlRect = sk_tool_utils::compute_central_occluder(SkRRect::MakeOval(pathRect));
-        } else if (path.isRRect(&pathRRect)) {
-            *occlRect = sk_tool_utils::compute_central_occluder(pathRRect);
-        } else if (path.isRect(occlRect)) {
-            // the inverse transform for the spot shadow occluder doesn't always get us
-            // back to exactly the same position, so deducting a little slop
-            occlRect->inset(1, 1);
-        } else {
-            *occlRect = SkRect::MakeEmpty();
-        }
-    }
-
-    void drawAmbientShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue, 
-                           SkScalar ambientAlpha) {
-
-        if (ambientAlpha <= 0) {
-            return;
-        }
-
-        const SkScalar kHeightFactor = 1.f / 128.f;
-        const SkScalar kGeomFactor = 64;
-
-        SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
-        SkScalar radius = zValue*kHeightFactor*kGeomFactor;
-
-        // occlude blur
-        SkRect occlRect;
-        GetOcclRect(path, &occlRect);
-        sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
-                                                        SkBlurMask::ConvertRadiusToSigma(radius),
-                                                        occlRect,
-                                                        SkBlurMaskFilter::kNone_BlurFlag);
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-        paint.setMaskFilter(std::move(mf));
-        paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
-                                    ? 255
-                                    : (unsigned char)(ambientAlpha*umbraAlpha*255.999f), 0, 0, 0));
-        canvas->drawPath(path, paint);
-
-        // draw occlusion rect
-#if DRAW_OCCL_RECT
-        SkPaint stroke;
-        stroke.setStyle(SkPaint::kStroke_Style);
-        stroke.setColor(SK_ColorBLUE);
-        canvas->drawRect(occlRect, stroke);
-#endif
-    }
-
-    void drawAmbientShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
-                              SkScalar ambientAlpha) {
-
-        if (ambientAlpha <= 0) {
-            return;
-        }
-
-        const SkScalar kHeightFactor = 1.f / 128.f;
-        const SkScalar kGeomFactor = 64;
-
-        SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
-        SkScalar radius = zValue*kHeightFactor*kGeomFactor;
-        // distance to outer of edge of geometry from original shape edge
-        SkScalar offset = radius*umbraAlpha;
-
-        SkRect pathRect;
-        SkRRect pathRRect;
-        SkScalar scaleFactors[2];
-        if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
-            return;
-        }
-        if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 64 ||
-            !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
-              (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
-              path.isRect(&pathRect))) {
-            this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
-            return;
-        }
-
-        // For all of these, we inset the offset rect by half the radius to get our stroke shape.
-        SkScalar strokeOutset = offset - SK_ScalarHalf*radius;
-        // Make sure we'll have a radius of at least 0.5 after xform
-        if (strokeOutset*scaleFactors[0] < 0.5f) {
-            strokeOutset = 0.5f / scaleFactors[0];
-        }
-        if (path.isOval(nullptr)) {
-            pathRect.outset(strokeOutset, strokeOutset);
-            pathRRect = SkRRect::MakeOval(pathRect);
-        } else if (path.isRect(nullptr)) {
-            pathRect.outset(strokeOutset, strokeOutset);
-            pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
-        } else {
-            pathRRect.outset(strokeOutset, strokeOutset);
-        }
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-        paint.setStyle(SkPaint::kStroke_Style);
-        // we outset the stroke a little to cover up AA on the interior edge
-        SkScalar pad = 0.5f;
-        paint.setStrokeWidth(radius + 2*pad);
-        // handle scale of radius and pad due to CTM
-        radius *= scaleFactors[0];
-        pad *= scaleFactors[0];
-        SkASSERT(radius < 16384);
-        SkASSERT(pad < 64);
-        // Convert radius to 14.2 fixed point and place in the R & G components.
-        // Convert pad to 6.2 fixed point and place in the B component.
-        uint16_t iRadius = (uint16_t)(radius*4.0f);
-        unsigned char alpha = (unsigned char)(ambientAlpha*255.999f);
-        paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
-                                      iRadius >> 8, iRadius & 0xff,
-                                      (unsigned char)(4.0f*pad)));
-
-        paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLACK, SkBlendMode::kModulate));
-        paint.setShader(SkGaussianEdgeShader::Make());
-        canvas->drawRRect(pathRRect, paint);
-    }
-
-    void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
-                        SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
-        if (spotAlpha <= 0) {
-            return;
-        }
-
-        SkScalar zRatio = zValue / (lightPos.fZ - zValue);
-        if (zRatio < 0.0f) {
-            zRatio = 0.0f;
-        } else if (zRatio > 0.95f) {
-            zRatio = 0.95f;
-        }
-        SkScalar blurRadius = lightWidth*zRatio;
-
-        // compute the transformation params
-        SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
-        SkMatrix ctmInverse;
-        if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
-            return;
-        }
-        SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
-        ctmInverse.mapPoints(&lightPos2D, 1);
-        SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
-                                       zRatio*(center.fY - lightPos2D.fY));
-        SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
-
-        SkAutoCanvasRestore acr(canvas, true);
-
-        sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
-                                                        SkBlurMask::ConvertRadiusToSigma(blurRadius),
-                                                        SkBlurMaskFilter::kNone_BlurFlag);
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-        paint.setMaskFilter(std::move(mf));
-        paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
-                                                ? 255 
-                                                : (unsigned char)(spotAlpha*255.999f), 0, 0, 0));
-
-        // apply transformation to shadow
-        canvas->scale(scale, scale);
-        canvas->translate(offset.fX, offset.fY);
-        canvas->drawPath(path, paint);
-    }
-
-    void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
-                        SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
-        if (spotAlpha <= 0) {
-            return;
-        }
-
-        SkScalar zRatio = zValue / (lightPos.fZ - zValue);
-        if (zRatio < 0.0f) {
-            zRatio = 0.0f;
-        } else if (zRatio > 0.95f) {
-            zRatio = 0.95f;
-        }
-        SkScalar radius = 2.0f*lightWidth*zRatio;
-
-        SkRect pathRect;
-        SkRRect pathRRect;
-        SkScalar scaleFactors[2];
-        if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
-            return;
-        }
-        if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 16384 ||
-            !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
-              (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
-              path.isRect(&pathRect))) {
-            this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
-            return;
-        }
-
-        // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
-        const SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
-        if (path.isOval(nullptr)) {
-            pathRRect = SkRRect::MakeOval(pathRect);
-        } else if (path.isRect(nullptr)) {
-            pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
-        } else {
-            if (pathRRect.getSimpleRadii().fX < minRadius) {
-                pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
-            }
-        }
-
-        // compute the scale and translation for the shadow
-        SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
-        SkRRect shadowRRect;
-        pathRRect.transform(SkMatrix::MakeScale(scale, scale), &shadowRRect);
-        SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY());
-        SkMatrix ctmInverse;
-        if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
-            return;
-        }
-        SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
-        ctmInverse.mapPoints(&lightPos2D, 1);
-        SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
-                                       zRatio*(center.fY - lightPos2D.fY));
-        SkAutoCanvasRestore acr(canvas, true);
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-        // We want to extend the stroked area in so that it meets up with the caster
-        // geometry. The stroked geometry will, by definition already be inset half the
-        // stroke width but we also have to account for the scaling.
-        // We also add 1/2 to cover up AA on the interior edge.
-        SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(pathRect.fLeft),
-                                                              SkTAbs(pathRect.fRight)),
-                                                       SkTMax(SkTAbs(pathRect.fTop),
-                                                              SkTAbs(pathRect.fBottom)));
-        SkScalar insetAmount = offset.length() - (0.5f * radius) + scaleOffset + 0.5f;
-
-        // compute area
-        SkScalar strokeWidth = radius + insetAmount;
-        SkScalar strokedArea = 2.0f*strokeWidth*(shadowRRect.width() + shadowRRect.height());
-        SkScalar filledArea = (shadowRRect.height() + radius)*(shadowRRect.width() + radius);
-        // If the area of the stroked geometry is larger than the fill geometry, or
-        // if our pad is too big to convert to 6.2 fixed point, just fill it.
-        if (strokedArea > filledArea) {
-            paint.setStyle(SkPaint::kStrokeAndFill_Style);
-            paint.setStrokeWidth(radius);
-        } else {
-            // Since we can't have unequal strokes, inset the shadow rect so the inner
-            // and outer edges of the stroke will land where we want.
-            SkRect insetRect = shadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
-            SkScalar insetRad = SkTMax(shadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
-                                       minRadius);
-
-            shadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
-            paint.setStyle(SkPaint::kStroke_Style);
-            paint.setStrokeWidth(strokeWidth);
-        }
-        paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLACK, SkBlendMode::kModulate));
-        paint.setShader(SkGaussianEdgeShader::Make());
-        // handle scale of radius due to CTM
-        radius *= scaleFactors[0];
-        // don't need to scale pad as it was computed from the transformed offset
-        SkASSERT(radius < 16384);
-        SkScalar pad = 0;
-        SkASSERT(pad < 64);
-        // Convert radius to 14.2 fixed point and place in the R & G components.
-        // Convert pad to 6.2 fixed point and place in the B component.
-        uint16_t iRadius = (uint16_t)(radius*4.0f);
-        unsigned char alpha = (unsigned char)(spotAlpha*255.999f);
-        paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
-                                      iRadius >> 8, iRadius & 0xff,
-                                      (unsigned char)(4.0f*pad)));
-
-        // apply transformation to shadow
-        canvas->translate(offset.fX, offset.fY);
-        canvas->drawRRect(shadowRRect, paint);
-    }
-
     void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
                           std::function<SkScalar(SkScalar, SkScalar)> zFunc,
                           const SkPaint& paint, SkScalar ambientAlpha,
                           const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
-#ifdef USE_SHADOW_UTILS
-        SkScalar zValue = zFunc(0, 0);
-        if (fUseAlt) {
-            if (fShowAmbient) {
-                this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
-            }
-            if (fShowSpot) {
-                this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
-            }
-        } else {
-            if (!fShowAmbient) {
-                ambientAlpha = 0;
-            }
-            if (!fShowSpot) {
-                spotAlpha = 0;
-            }
-
-            //SkShadowUtils::DrawShadow(canvas, path,
-            //                          zValue,
-            //                          lightPos, lightWidth,
-            //                          ambientAlpha, spotAlpha, SK_ColorBLACK);
-            SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc,
-                                              lightPos, lightWidth,
-                                              ambientAlpha, spotAlpha, SK_ColorBLACK);
+        if (!fShowAmbient) {
+            ambientAlpha = 0;
         }
-#else
-        if (fShowAmbient) {
-            if (fUseAlt) {
-                this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
-            } else {
-                this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
-            }
+        if (!fShowSpot) {
+            spotAlpha = 0;
         }
-        if (fShowSpot) {
-            if (fUseAlt) {
-                this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
-            } else {
-                this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
-            }
+        uint32_t flags = 0;
+        if (fUseAlt) {
+            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
         }
-#endif
+        //SkShadowUtils::DrawShadow(canvas, path,
+        //                          zValue,
+        //                          lightPos, lightWidth,
+        //                          ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
+        SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc,
+                                          lightPos, lightWidth,
+                                          ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
 
         if (fShowObject) {
             canvas->drawPath(path, paint);
@@ -577,27 +275,6 @@ protected:
         return true;
     }
 
-protected:
-    SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
-        return new SkView::Click(this);
-    }
-
-    bool onClick(Click *click) override {
-        SkScalar x = click->fCurr.fX;
-        SkScalar y = click->fCurr.fY;
-
-        SkScalar dx = x - click->fPrev.fX;
-        SkScalar dy = y - click->fPrev.fY;
-
-        if (dx != 0 || dy != 0) {
-            fLightPos.fX += dx;
-            fLightPos.fY += dy;
-            this->inval(nullptr);
-        }
-
-        return true;
-    }
-
 private:
     typedef SampleView INHERITED;
 };
index 95b08d2..a37c173 100644 (file)
@@ -23,7 +23,7 @@ public:
         fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
         if (!args.fGpImplementsDistanceVector) {
             fragBuilder->codeAppendf("// assuming interpolant is set in vertex colors\n");
-            fragBuilder->codeAppendf("float factor = 1.0 - color.b;");
+            fragBuilder->codeAppendf("float factor = 1.0 - color.a;");
         } else {
             fragBuilder->codeAppendf("// using distance to edge to compute interpolant\n");
             fragBuilder->codeAppend("float radius = color.r*256.0*64.0 + color.g*64.0;");
@@ -37,14 +37,10 @@ public:
                 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
                 break;
             case GrBlurredEdgeFP::kSmoothstep_Mode:
-                fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);");
+                fragBuilder->codeAppend("factor = smoothstep(1.0, 0.0, factor);");
                 break;
         }
-        if (!args.fGpImplementsDistanceVector) {
-            fragBuilder->codeAppendf("%s = vec4(factor*color.g);", args.fOutputColor);
-        } else {
-            fragBuilder->codeAppendf("%s = vec4(factor*color.a);", args.fOutputColor);
-        }
+        fragBuilder->codeAppendf("%s = vec4(factor);", args.fOutputColor);
     }
 
 protected:
index 36df514..32a1142 100755 (executable)
@@ -327,8 +327,7 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) {
 class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
 public:
     SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
-                               SkShadowTessellator::HeightFunc heightFunc,
-                               SkScalar ambientAlpha, bool transparent);
+                               SkShadowTessellator::HeightFunc heightFunc, bool transparent);
 
 private:
     void handleLine(const SkPoint& p) override;
@@ -343,10 +342,9 @@ private:
     }
     SkColor umbraColor(SkScalar z) {
         SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(z*kHeightFactor, 0.0f)));
-        return SkColorSetARGB(255, 0, fAmbientAlpha * 255.9999f, umbraAlpha * 255.9999f);
+        return SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
     }
 
-    SkScalar            fAmbientAlpha;
     int                 fCentroidCount;
 
     typedef SkBaseShadowTessellator INHERITED;
@@ -355,10 +353,8 @@ private:
 SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
                                                        const SkMatrix& ctm,
                                                        SkShadowTessellator::HeightFunc heightFunc,
-                                                       SkScalar ambientAlpha,
                                                        bool transparent)
-        : INHERITED(heightFunc, transparent)
-        , fAmbientAlpha(ambientAlpha) {
+        : INHERITED(heightFunc, transparent) {
     // Set base colors
     SkScalar occluderHeight = heightFunc(0, 0);
     SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f)));
@@ -366,8 +362,8 @@ SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
     // 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.
-    fUmbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, umbraAlpha * 255.9999f);
-    fPenumbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, 0);
+    fUmbraColor = SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
+    fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
 
     // make sure we're not below the canvas plane
     this->setZOffset(path.getBounds(), ctm.hasPerspective());
@@ -654,9 +650,8 @@ void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto
 class SkSpotShadowTessellator : public SkBaseShadowTessellator {
 public:
     SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
-                            SkShadowTessellator::HeightFunc heightFunc,
-                            const SkPoint3& lightPos, SkScalar lightRadius,
-                            SkScalar spotAlpha, bool transparent);
+                            SkShadowTessellator::HeightFunc heightFunc, const SkPoint3& lightPos,
+                            SkScalar lightRadius, bool transparent);
 
 private:
     void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
@@ -700,7 +695,7 @@ private:
 SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
                                                  SkShadowTessellator::HeightFunc heightFunc,
                                                  const SkPoint3& lightPos, SkScalar lightRadius,
-                                                 SkScalar spotAlpha, bool transparent)
+                                                 bool transparent)
     : INHERITED(heightFunc, transparent)
     , fLightZ(lightPos.fZ)
     , fLightRadius(lightRadius)
@@ -723,8 +718,8 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMat
     float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f);
     SkScalar radius = lightRadius * zRatio;
     fRadius = radius;
-    fUmbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 255);
-    fPenumbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 0);
+    fUmbraColor = SkColorSetARGB(255, 0, 0, 0);
+    fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
 
     // Compute the scale and translation for the spot shadow.
     SkMatrix shadowTransform;
@@ -1292,17 +1287,14 @@ void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector&
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
-                                                   HeightFunc heightFunc, SkScalar ambientAlpha,
-                                                   bool transparent) {
-    SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, ambientAlpha, transparent);
+                                                   HeightFunc heightFunc, bool transparent) {
+    SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, transparent);
     return ambientTess.releaseVertices();
 }
 
 sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
-                                                HeightFunc heightFunc,
-                                                const SkPoint3& lightPos, SkScalar lightRadius,
-                                                SkScalar spotAlpha, bool transparent) {
-    SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius,
-                                     spotAlpha, transparent);
+                                                HeightFunc heightFunc, const SkPoint3& lightPos,
+                                                SkScalar lightRadius,  bool transparent) {
+    SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius, transparent);
     return spotTess.releaseVertices();
 }
index f9f4a14..d6e784e 100644 (file)
@@ -26,7 +26,7 @@ typedef std::function<SkScalar(SkScalar, SkScalar)> HeightFunc;
  * If transparent is true, then the center of the ambient shadow will be filled in.
  */
 sk_sp<SkVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm,
-                              HeightFunc heightFunc, SkScalar ambientAlpha, bool transparent);
+                              HeightFunc heightFunc, bool transparent);
 
 /**
  * This function generates a spot shadow mesh for a path by walking the transformed path,
@@ -34,8 +34,7 @@ sk_sp<SkVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm,
  * The center will be clipped against the original path unless transparent is true.
  */
 sk_sp<SkVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm, HeightFunc heightFunc,
-                           const SkPoint3& lightPos, SkScalar lightRadius,
-                           SkScalar spotAlpha, bool transparent);
+                           const SkPoint3& lightPos, SkScalar lightRadius, bool transparent);
 }
 
 #endif
index 279ca73..430ea2c 100644 (file)
@@ -54,52 +54,52 @@ private:
 };
 
 static void build_table() {
-    SkDebugf("const uint16_t gByteExpU16Table[256] = {");
+    SkDebugf("const uint8_t gByteExpU8Table[256] = {");
     for (int i = 0; i <= 255; ++i) {
         if (!(i % 8)) {
             SkDebugf("\n");
         }
         SkScalar factor = SK_Scalar1 - i / 255.f;
         factor = SkScalarExp(-factor * factor * 4) - 0.018f;
-        int v = (int)(factor * 65536);
-        SkDebugf(" 0x%04X,", v);
+        int v = (int)(factor * 255.9f);
+        SkDebugf(" 0x%02X,", v);
     }
     SkDebugf("\n};\n");
 }
 
-const uint16_t gByteExpU16Table[256] = {
-    0x0014, 0x003A, 0x0062, 0x008A, 0x00B3, 0x00DE, 0x010A, 0x0136,
-    0x0165, 0x0194, 0x01C4, 0x01F6, 0x0229, 0x025E, 0x0294, 0x02CB,
-    0x0304, 0x033E, 0x0379, 0x03B7, 0x03F5, 0x0435, 0x0477, 0x04BB,
-    0x0500, 0x0546, 0x058F, 0x05D9, 0x0625, 0x0673, 0x06C3, 0x0714,
-    0x0768, 0x07BD, 0x0814, 0x086E, 0x08C9, 0x0926, 0x0986, 0x09E8,
-    0x0A4B, 0x0AB1, 0x0B1A, 0x0B84, 0x0BF1, 0x0C60, 0x0CD2, 0x0D46,
-    0x0DBC, 0x0E35, 0x0EB0, 0x0F2E, 0x0FAF, 0x1032, 0x10B7, 0x1140,
-    0x11CB, 0x1258, 0x12E9, 0x137C, 0x1412, 0x14AB, 0x1547, 0x15E6,
-    0x1688, 0x172D, 0x17D5, 0x187F, 0x192D, 0x19DE, 0x1A92, 0x1B4A,
-    0x1C04, 0x1CC2, 0x1D83, 0x1E47, 0x1F0E, 0x1FD9, 0x20A7, 0x2178,
-    0x224D, 0x2325, 0x2401, 0x24E0, 0x25C2, 0x26A8, 0x2792, 0x287F,
-    0x296F, 0x2A63, 0x2B5A, 0x2C56, 0x2D54, 0x2E56, 0x2F5C, 0x3065,
-    0x3172, 0x3283, 0x3397, 0x34AE, 0x35CA, 0x36E9, 0x380B, 0x3931,
-    0x3A5B, 0x3B88, 0x3CB9, 0x3DED, 0x3F25, 0x4061, 0x41A0, 0x42E2,
-    0x4428, 0x4572, 0x46BF, 0x480F, 0x4963, 0x4ABA, 0x4C14, 0x4D72,
-    0x4ED3, 0x5038, 0x519F, 0x530A, 0x5478, 0x55E9, 0x575D, 0x58D4,
-    0x5A4F, 0x5BCC, 0x5D4C, 0x5ECF, 0x6054, 0x61DD, 0x6368, 0x64F6,
-    0x6686, 0x6819, 0x69AE, 0x6B45, 0x6CDF, 0x6E7B, 0x701A, 0x71BA,
-    0x735D, 0x7501, 0x76A7, 0x784F, 0x79F9, 0x7BA4, 0x7D51, 0x7F00,
-    0x80AF, 0x8260, 0x8413, 0x85C6, 0x877A, 0x8930, 0x8AE6, 0x8C9C,
-    0x8E54, 0x900C, 0x91C4, 0x937D, 0x9535, 0x96EE, 0x98A7, 0x9A60,
-    0x9C18, 0x9DD1, 0x9F88, 0xA13F, 0xA2F6, 0xA4AB, 0xA660, 0xA814,
-    0xA9C6, 0xAB78, 0xAD27, 0xAED6, 0xB082, 0xB22D, 0xB3D6, 0xB57D,
-    0xB722, 0xB8C5, 0xBA65, 0xBC03, 0xBD9E, 0xBF37, 0xC0CD, 0xC25F,
-    0xC3EF, 0xC57B, 0xC704, 0xC889, 0xCA0B, 0xCB89, 0xCD04, 0xCE7A,
-    0xCFEC, 0xD15A, 0xD2C4, 0xD429, 0xD58A, 0xD6E6, 0xD83D, 0xD990,
-    0xDADD, 0xDC25, 0xDD68, 0xDEA6, 0xDFDE, 0xE111, 0xE23E, 0xE365,
-    0xE486, 0xE5A2, 0xE6B7, 0xE7C6, 0xE8CF, 0xE9D1, 0xEACD, 0xEBC3,
-    0xECB2, 0xED9A, 0xEE7C, 0xEF56, 0xF02A, 0xF0F6, 0xF1BC, 0xF27A,
-    0xF332, 0xF3E1, 0xF48A, 0xF52B, 0xF5C5, 0xF657, 0xF6E1, 0xF764,
-    0xF7DF, 0xF852, 0xF8BE, 0xF922, 0xF97E, 0xF9D2, 0xFA1E, 0xFA62,
-    0xFA9F, 0xFAD3, 0xFAFF, 0xFB23, 0xFB40, 0xFB54, 0xFB60, 0xFB64,
+const uint8_t gByteExpU8Table[256] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
+    0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07,
+    0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
+    0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D,
+    0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11,
+    0x11, 0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x15,
+    0x16, 0x17, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B,
+    0x1C, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21,
+    0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+    0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
+    0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
+    0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4C, 0x4D,
+    0x4E, 0x50, 0x51, 0x53, 0x54, 0x55, 0x57, 0x58,
+    0x5A, 0x5B, 0x5D, 0x5E, 0x60, 0x61, 0x63, 0x64,
+    0x66, 0x68, 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x71,
+    0x73, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7E,
+    0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8A, 0x8C,
+    0x8E, 0x8F, 0x91, 0x93, 0x95, 0x96, 0x98, 0x9A,
+    0x9C, 0x9D, 0x9F, 0xA1, 0xA2, 0xA4, 0xA6, 0xA8,
+    0xA9, 0xAB, 0xAD, 0xAE, 0xB0, 0xB2, 0xB3, 0xB5,
+    0xB7, 0xB8, 0xBA, 0xBB, 0xBD, 0xBF, 0xC0, 0xC2,
+    0xC3, 0xC5, 0xC6, 0xC8, 0xC9, 0xCB, 0xCC, 0xCE,
+    0xCF, 0xD1, 0xD2, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9,
+    0xDA, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE3,
+    0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
+    0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF0, 0xF1, 0xF2,
+    0xF3, 0xF3, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7,
+    0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA,
+    0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
 };
 
 void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
@@ -109,7 +109,7 @@ void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMCol
     }
     for (int i = 0; i < count; ++i) {
         SkPMColor c = src[i];
-        uint8_t a = gByteExpU16Table[SkGetPackedB32(c)] * SkGetPackedG32(c) >> 16;
+        uint8_t a = gByteExpU8Table[SkGetPackedA32(c)];
         dst[i] = SkPackARGB32(a, a, a, a);
     }
 }
@@ -143,12 +143,10 @@ uint64_t resource_cache_shared_id() {
 /** Factory for an ambient shadow mesh with particular shadow properties. */
 struct AmbientVerticesFactory {
     SkScalar fOccluderHeight = SK_ScalarNaN;  // NaN so that isCompatible will fail until init'ed.
-    SkScalar fAmbientAlpha;
     bool fTransparent;
 
     bool isCompatible(const AmbientVerticesFactory& that, SkVector* translate) const {
-        if (fOccluderHeight != that.fOccluderHeight || fAmbientAlpha != that.fAmbientAlpha ||
-            fTransparent != that.fTransparent) {
+        if (fOccluderHeight != that.fOccluderHeight || fTransparent != that.fTransparent) {
             return false;
         }
         translate->set(0, 0);
@@ -159,7 +157,7 @@ struct AmbientVerticesFactory {
         SkScalar z = fOccluderHeight;
         return SkShadowTessellator::MakeAmbient(path, ctm,
                                                 [z](SkScalar, SkScalar) { return z; },
-                                                fAmbientAlpha, fTransparent);
+                                                fTransparent);
     }
 };
 
@@ -178,13 +176,11 @@ struct SpotVerticesFactory {
     SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed.
     SkPoint3 fDevLightPos;
     SkScalar fLightRadius;
-    SkScalar fSpotAlpha;
     OccluderType fOccluderType;
 
     bool isCompatible(const SpotVerticesFactory& that, SkVector* translate) const {
         if (fOccluderHeight != that.fOccluderHeight || fDevLightPos.fZ != that.fDevLightPos.fZ ||
-            fLightRadius != that.fLightRadius || fSpotAlpha != that.fSpotAlpha ||
-            fOccluderType != that.fOccluderType) {
+            fLightRadius != that.fLightRadius || fOccluderType != that.fOccluderType) {
             return false;
         }
         switch (fOccluderType) {
@@ -212,8 +208,7 @@ struct SpotVerticesFactory {
         SkScalar z = fOccluderHeight;
         return SkShadowTessellator::MakeSpot(path, ctm,
                                              [z](SkScalar, SkScalar) -> SkScalar { return z; },
-                                             fDevLightPos, fLightRadius,
-                                             fSpotAlpha, transparent);
+                                             fDevLightPos, fLightRadius, transparent);
     }
 };
 
@@ -569,14 +564,21 @@ static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar
     return false;
 }
 
+static SkColor compute_render_color(SkColor color, float alpha) {
+    return SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
+                          SkColorGetG(color), SkColorGetB(color));
+}
+
 // 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& devLightPos, SkScalar lightRadius,
                                SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
                                uint32_t flags, SkResourceCache* cache) {
     // try fast paths
-    if (draw_analytic_shadows(canvas, path, occluderHeight, devLightPos, lightRadius,
-                              ambientAlpha, spotAlpha, color, flags)) {
+    bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+    if (!skipAnalytic && draw_analytic_shadows(canvas, path, occluderHeight, devLightPos,
+                                               lightRadius, ambientAlpha, spotAlpha, color,
+                                               flags)) {
         return;
     }
 
@@ -592,10 +594,10 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
         ambientAlpha = SkTMin(ambientAlpha, 1.f);
         AmbientVerticesFactory factory;
         factory.fOccluderHeight = occluderHeight;
-        factory.fAmbientAlpha = ambientAlpha;
         factory.fTransparent = transparent;
 
-        draw_shadow(factory, canvas, shadowedPath, color, cache);
+        SkColor renderColor = compute_render_color(color, ambientAlpha);
+        draw_shadow(factory, canvas, shadowedPath, renderColor, cache);
     }
 
     if (spotAlpha > 0) {
@@ -614,7 +616,6 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
         factory.fOccluderHeight = occluderHeight;
         factory.fDevLightPos = devLightPos;
         factory.fLightRadius = lightRadius;
-        factory.fSpotAlpha = spotAlpha;
 
         SkRRect rrect;
         if (transparent) {
@@ -653,7 +654,9 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
         if (factory.fOccluderType == SpotVerticesFactory::OccluderType::kOpaque) {
             factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
         }
-        draw_shadow(factory, canvas, shadowedPath, color, cache);
+
+        SkColor renderColor = compute_render_color(color, spotAlpha);
+        draw_shadow(factory, canvas, shadowedPath, renderColor, cache);
     }
 }
 
@@ -665,8 +668,10 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
                                        SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
                                        uint32_t flags) {
     // try fast paths
-    if (draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos, lightRadius,
-                              ambientAlpha, spotAlpha, color, flags)) {
+    bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+    if (!skipAnalytic && draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos,
+                                               lightRadius, ambientAlpha, spotAlpha, color,
+                                               flags)) {
         return;
     }
 
@@ -679,13 +684,13 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
     if (ambientAlpha > 0) {
         ambientAlpha = SkTMin(ambientAlpha, 1.f);
         sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix,
-                                                                      heightFunc, ambientAlpha,
-                                                                      transparent);
+                                                                      heightFunc, transparent);
+        SkColor renderColor = compute_render_color(color, ambientAlpha);
         SkPaint paint;
         // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
         // result of that against our 'color' param.
         paint.setColorFilter(SkColorFilter::MakeComposeFilter(
-            SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
+            SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
             SkGaussianColorFilter::Make()));
         canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
     }
@@ -694,12 +699,13 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
         spotAlpha = SkTMin(spotAlpha, 1.f);
         sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, heightFunc,
                                                                    lightPos, lightRadius,
-                                                                   spotAlpha, transparent);
+                                                                   transparent);
+        SkColor renderColor = compute_render_color(color, spotAlpha);
         SkPaint paint;
         // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
         // result of that against our 'color' param.
         paint.setColorFilter(SkColorFilter::MakeComposeFilter(
-            SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
+            SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
             SkGaussianColorFilter::Make()));
         canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
     }
index 5699014..f83e44a 100644 (file)
 
 void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm,
                        bool expectSuccess) {
-    static constexpr SkScalar kAmbientAlpha = 0.25f;
-    static constexpr SkScalar kSpotAlpha = 0.25f;
 
     auto heightFunc = [] (SkScalar, SkScalar) { return 4; };
 
-    auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, kAmbientAlpha, true);
+    auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, true);
     if (expectSuccess != SkToBool(verts)) {
         ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
                expectSuccess ? "succeed" : "fail");
     }
-    verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, kAmbientAlpha, false);
+    verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, false);
     if (expectSuccess != SkToBool(verts)) {
         ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
                expectSuccess ? "succeed" : "fail");
     }
-    verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f,
-                                          kSpotAlpha, false);
+    verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false);
     if (expectSuccess != SkToBool(verts)) {
         ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
                expectSuccess ? "succeed" : "fail");
     }
-    verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f,
-                                          kSpotAlpha, false);
+    verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false);
     if (expectSuccess != SkToBool(verts)) {
         ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
                expectSuccess ? "succeed" : "fail");