[svg] Implement feDiffuseLighting

https://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement

- Add SkSVGFeDiffuseLighting node
- Move distant light source direction computation into a method on
  SkSVGFeDistantLight
- Implement distant and point light sources for feDiffuseLighting

Bug: skia:10841
Change-Id: I74b8b9e04be5d2c5ac9f912d015dce96367040a1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/402645
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Tyler Denniston <tdenniston@google.com>
diff --git a/modules/svg/include/SkSVGFe.h b/modules/svg/include/SkSVGFe.h
index cbb0c45..25ed166 100644
--- a/modules/svg/include/SkSVGFe.h
+++ b/modules/svg/include/SkSVGFe.h
@@ -23,7 +23,8 @@
                node->tag() == SkSVGTag::kFeGaussianBlur || node->tag() == SkSVGTag::kFeOffset ||
                node->tag() == SkSVGTag::kFeBlend || node->tag() == SkSVGTag::kFeMorphology ||
                node->tag() == SkSVGTag::kFeDisplacementMap ||
-               node->tag() == SkSVGTag::kFeSpecularLighting;
+               node->tag() == SkSVGTag::kFeSpecularLighting ||
+               node->tag() == SkSVGTag::kFeDiffuseLighting;
     }
 
     sk_sp<SkImageFilter> makeImageFilter(const SkSVGRenderContext& ctx,
diff --git a/modules/svg/include/SkSVGFeLightSource.h b/modules/svg/include/SkSVGFeLightSource.h
index 75f0074..643c150 100644
--- a/modules/svg/include/SkSVGFeLightSource.h
+++ b/modules/svg/include/SkSVGFeLightSource.h
@@ -8,6 +8,7 @@
 #ifndef SkSVGFeLightSource_DEFINED
 #define SkSVGFeLightSource_DEFINED
 
+#include "include/core/SkPoint3.h"
 #include "modules/svg/include/SkSVGHiddenContainer.h"
 #include "modules/svg/include/SkSVGTypes.h"
 
@@ -30,6 +31,8 @@
         return sk_sp<SkSVGFeDistantLight>(new SkSVGFeDistantLight());
     }
 
+    SkPoint3 computeDirection() const;
+
     SVG_ATTR(Azimuth  , SkSVGNumberType, 0)
     SVG_ATTR(Elevation, SkSVGNumberType, 0)
 
diff --git a/modules/svg/include/SkSVGFeLighting.h b/modules/svg/include/SkSVGFeLighting.h
index 3a0da67..46b759a 100644
--- a/modules/svg/include/SkSVGFeLighting.h
+++ b/modules/svg/include/SkSVGFeLighting.h
@@ -80,4 +80,29 @@
     using INHERITED = SkSVGFeLighting;
 };
 
+class SkSVGFeDiffuseLighting final : public SkSVGFeLighting {
+public:
+    static sk_sp<SkSVGFeDiffuseLighting> Make() {
+        return sk_sp<SkSVGFeDiffuseLighting>(new SkSVGFeDiffuseLighting());
+    }
+
+    SVG_ATTR(DiffuseConstant, SkSVGNumberType, 1)
+
+protected:
+    bool parseAndSetAttribute(const char*, const char*) override;
+
+    sk_sp<SkImageFilter> makeDistantLight(const SkSVGRenderContext&,
+                                          const SkSVGFilterContext&,
+                                          const SkSVGFeDistantLight*) const final;
+
+    sk_sp<SkImageFilter> makePointLight(const SkSVGRenderContext&,
+                                        const SkSVGFilterContext&,
+                                        const SkSVGFePointLight*) const final;
+
+private:
+    SkSVGFeDiffuseLighting() : INHERITED(SkSVGTag::kFeDiffuseLighting) {}
+
+    using INHERITED = SkSVGFeLighting;
+};
+
 #endif  // SkSVGFeLighting_DEFINED
diff --git a/modules/svg/include/SkSVGNode.h b/modules/svg/include/SkSVGNode.h
index c4da7d5..357050f 100644
--- a/modules/svg/include/SkSVGNode.h
+++ b/modules/svg/include/SkSVGNode.h
@@ -28,6 +28,7 @@
     kFeBlend,
     kFeColorMatrix,
     kFeComposite,
+    kFeDiffuseLighting,
     kFeDisplacementMap,
     kFeDistantLight,
     kFeFlood,
diff --git a/modules/svg/src/SkSVGDOM.cpp b/modules/svg/src/SkSVGDOM.cpp
index 4d26afe..7d0cb8f 100644
--- a/modules/svg/src/SkSVGDOM.cpp
+++ b/modules/svg/src/SkSVGDOM.cpp
@@ -242,6 +242,7 @@
     { "feBlend"           , []() -> sk_sp<SkSVGNode> { return SkSVGFeBlend::Make();            }},
     { "feColorMatrix"     , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make();      }},
     { "feComposite"       , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make();        }},
+    { "feDiffuseLighting" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDiffuseLighting::Make();  }},
     { "feDisplacementMap" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDisplacementMap::Make();  }},
     { "feDistantLight"    , []() -> sk_sp<SkSVGNode> { return SkSVGFeDistantLight::Make();     }},
     { "feFlood"           , []() -> sk_sp<SkSVGNode> { return SkSVGFeFlood::Make();            }},
diff --git a/modules/svg/src/SkSVGFeLightSource.cpp b/modules/svg/src/SkSVGFeLightSource.cpp
index f1f74af..2f05957 100644
--- a/modules/svg/src/SkSVGFeLightSource.cpp
+++ b/modules/svg/src/SkSVGFeLightSource.cpp
@@ -9,6 +9,18 @@
 #include "modules/svg/include/SkSVGFeLightSource.h"
 #include "modules/svg/include/SkSVGValue.h"
 
+SkPoint3 SkSVGFeDistantLight::computeDirection() const {
+    // Computing direction from azimuth+elevation is two 3D rotations:
+    //  - Rotate [1,0,0] about y axis first (elevation)
+    //  - Rotate result about z axis (azimuth)
+    // Which is just the first column vector in the 3x3 matrix Rz*Ry.
+    const float azimuthRad = SkDegreesToRadians(fAzimuth);
+    const float elevationRad = SkDegreesToRadians(fElevation);
+    const float sinAzimuth = sinf(azimuthRad), cosAzimuth = cosf(azimuthRad);
+    const float sinElevation = sinf(elevationRad), cosElevation = cosf(elevationRad);
+    return SkPoint3::Make(cosAzimuth * cosElevation, sinAzimuth * cosElevation, sinElevation);
+}
+
 bool SkSVGFeDistantLight::parseAndSetAttribute(const char* n, const char* v) {
     return INHERITED::parseAndSetAttribute(n, v) ||
            this->setAzimuth(SkSVGAttributeParser::parse<SkSVGNumberType>("azimuth", n, v)) ||
diff --git a/modules/svg/src/SkSVGFeLighting.cpp b/modules/svg/src/SkSVGFeLighting.cpp
index 14576ba..0882b00 100644
--- a/modules/svg/src/SkSVGFeLighting.cpp
+++ b/modules/svg/src/SkSVGFeLighting.cpp
@@ -95,19 +95,7 @@
         const SkSVGRenderContext& ctx,
         const SkSVGFilterContext& fctx,
         const SkSVGFeDistantLight* light) const {
-    const auto computeDirection = [](float azimuth, float elevation) -> SkPoint3 {
-        // Computing direction from azimuth+elevation is two 3D rotations:
-        //  - Rotate [1,0,0] about y axis first (elevation)
-        //  - Rotate result about z axis (azimuth)
-        // Which is just the first column vector in the 3x3 matrix Rz*Ry.
-        const float azimuthRad = SkDegreesToRadians(azimuth);
-        const float elevationRad = SkDegreesToRadians(elevation);
-        const float sinAzimuth = sinf(azimuthRad), cosAzimuth = cosf(azimuthRad);
-        const float sinElevation = sinf(elevationRad), cosElevation = cosf(elevationRad);
-        return SkPoint3::Make(cosAzimuth * cosElevation, sinAzimuth * cosElevation, sinElevation);
-    };
-
-    const SkPoint3 dir = computeDirection(light->getAzimuth(), light->getElevation());
+    const SkPoint3 dir = light->computeDirection();
     return SkImageFilters::DistantLitSpecular(
             this->resolveXYZ(ctx, fctx, dir.fX, dir.fY, dir.fZ),
             this->resolveLightingColor(ctx),
@@ -130,3 +118,35 @@
             fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
             this->resolveFilterSubregion(ctx, fctx));
 }
+
+bool SkSVGFeDiffuseLighting::parseAndSetAttribute(const char* n, const char* v) {
+    return INHERITED::parseAndSetAttribute(n, v) ||
+           this->setDiffuseConstant(
+                   SkSVGAttributeParser::parse<SkSVGNumberType>("diffuseConstant", n, v));
+}
+
+sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makeDistantLight(
+        const SkSVGRenderContext& ctx,
+        const SkSVGFilterContext& fctx,
+        const SkSVGFeDistantLight* light) const {
+    const SkPoint3 dir = light->computeDirection();
+    return SkImageFilters::DistantLitDiffuse(
+            this->resolveXYZ(ctx, fctx, dir.fX, dir.fY, dir.fZ),
+            this->resolveLightingColor(ctx),
+            this->getSurfaceScale(),
+            this->getDiffuseConstant(),
+            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
+            this->resolveFilterSubregion(ctx, fctx));
+}
+
+sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makePointLight(const SkSVGRenderContext& ctx,
+                                                            const SkSVGFilterContext& fctx,
+                                                            const SkSVGFePointLight* light) const {
+    return SkImageFilters::PointLitDiffuse(
+            this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
+            this->resolveLightingColor(ctx),
+            this->getSurfaceScale(),
+            this->getDiffuseConstant(),
+            fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
+            this->resolveFilterSubregion(ctx, fctx));
+}