Fix color-filter to apply to SVG colors
https://bugs.webkit.org/show_bug.cgi?id=185113
rdar://problem/39665082

Reviewed by Dean Jackson.
Source/WebCore:

Convert SVG colors through color-filter operations for the places in SVG
that use color, namely fill and stroke, gradients, lighting colors and
drop-shadow.

Test: css3/color-filters/svg/color-filter-inline-svg.html

* rendering/svg/RenderSVGResourceGradient.cpp:
(WebCore::RenderSVGResourceGradient::applyResource):
* rendering/svg/RenderSVGResourceGradient.h:
* rendering/svg/RenderSVGResourceLinearGradient.cpp:
(WebCore::RenderSVGResourceLinearGradient::buildGradient const):
* rendering/svg/RenderSVGResourceLinearGradient.h:
* rendering/svg/RenderSVGResourceRadialGradient.cpp:
(WebCore::RenderSVGResourceRadialGradient::buildGradient const):
* rendering/svg/RenderSVGResourceRadialGradient.h:
* rendering/svg/RenderSVGResourceSolidColor.cpp:
(WebCore::RenderSVGResourceSolidColor::applyResource):
* svg/SVGFEDiffuseLightingElement.cpp:
(WebCore::SVGFEDiffuseLightingElement::setFilterEffectAttribute):
(WebCore::SVGFEDiffuseLightingElement::build):
* svg/SVGFEDropShadowElement.cpp:
(WebCore::SVGFEDropShadowElement::build):
* svg/SVGFEFloodElement.cpp:
(WebCore::SVGFEFloodElement::build):
* svg/SVGFESpecularLightingElement.cpp:
(WebCore::SVGFESpecularLightingElement::setFilterEffectAttribute):
(WebCore::SVGFESpecularLightingElement::build):

LayoutTests:

* css3/color-filters/svg/color-filter-inline-svg-expected.html: Added.
* css3/color-filters/svg/color-filter-inline-svg.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231153 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index c0b2e45..7534cf5 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,14 @@
+2018-04-28  Simon Fraser  <simon.fraser@apple.com>
+
+        Fix color-filter to apply to SVG colors
+        https://bugs.webkit.org/show_bug.cgi?id=185113
+        rdar://problem/39665082
+
+        Reviewed by Dean Jackson.
+
+        * css3/color-filters/svg/color-filter-inline-svg-expected.html: Added.
+        * css3/color-filters/svg/color-filter-inline-svg.html: Added.
+
 2018-04-27  Ryan Haddad  <ryanhaddad@apple.com>
 
         Unreviewed test gardening for iOS and macOS.
diff --git a/LayoutTests/css3/color-filters/svg/color-filter-inline-svg-expected.html b/LayoutTests/css3/color-filters/svg/color-filter-inline-svg-expected.html
new file mode 100644
index 0000000..d08c182
--- /dev/null
+++ b/LayoutTests/css3/color-filters/svg/color-filter-inline-svg-expected.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>CSS Test: color-filter reference</title>
+        <link rel="author" title="Apple" href="http://www.apple.com/">
+
+        <style>
+            body {
+                margin: 0;
+            }
+        </style>
+    </head>
+<body>
+
+<svg viewBox="0 0 800 600" style="width: 800px; height: 600px">
+    <defs>
+        <radialGradient id="grad">
+            <stop offset="0" stop-color="cyan" />
+            <stop offset="0.5" stop-color="green" />
+            <stop offset="0.75" stop-color="blue" />
+        </radialGradient>
+
+        <filter id="flood" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+            <feFlood flood-color="green" />
+        </filter>
+
+        <filter id="diffuse-light" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+            <feDiffuseLighting lighting-color="green">
+                <feDistantLight azimuth="100" elevation="100"/>
+            </feDiffuseLighting>
+        </filter>
+
+        <filter id="specular-light" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+            <feSpecularLighting surfaceScale="2" specularExponent="2" specularConstant="2" lighting-color="green">
+                <fePointLight x="20" y="20" z="2"/>
+            </feSpecularLighting>
+        </filter>
+
+        <filter id="shadow" x="0" y="0" width="160%" height="160%">
+            <feDropShadow dx="50" dy="50" stdDeviation="0" flood-color="green" flood-opacity="1" />
+        </filter>
+
+        <pattern id="pattern" patternUnits="userSpaceOnUse" x="20" y="0" width="50" height="50">
+           <rect x="5" y="5" width="30" height="30" fill="green"/>
+        </pattern>
+    </defs>
+
+    <rect x="20" y="10" width="150" height="150" fill="url(#grad)" />
+
+    <rect x="200" y="10" width="150" height="150" fill="green" />
+    <rect x="400" y="10" width="150" height="150" fill="green" stroke="blue" stroke-width="15" />
+
+    <rect x="20" y="200" width="150" height="150" filter="url(#flood)"/>
+    <rect x="200" y="200" width="150" height="150" filter="url(#diffuse-light)"/>
+    <rect x="400" y="200" width="150" height="150" filter="url(#specular-light)"/>
+
+    <rect x="20" y="400" width="150" height="150" fill="url(#pattern)"/>
+
+    <rect x="200" y="400" width="100" height="100" fill="blue" filter="url(#shadow)"/>
+</svg>
+
+</body>
+</html>
diff --git a/LayoutTests/css3/color-filters/svg/color-filter-inline-svg.html b/LayoutTests/css3/color-filters/svg/color-filter-inline-svg.html
new file mode 100644
index 0000000..57ae6af
--- /dev/null
+++ b/LayoutTests/css3/color-filters/svg/color-filter-inline-svg.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html >
+    <head>
+        <title>CSS Test: color-filter affects colors in inline SVG</title>
+        <link rel="author" title="Apple" href="http://www.apple.com/">
+        <link rel="match" href="color-filter-inline-svg-expected.html">
+
+        <meta name="assert" content="color-filter affects colors in inline SVG">
+        <style>
+            html {
+                color-filter: invert();
+            }
+
+            body {
+                margin: 0;
+            }
+        </style>
+    </head>
+<body>
+
+<svg viewBox="0 0 800 600" style="width: 800px; height: 600px">
+    <defs>
+        <radialGradient id="grad">
+            <stop offset="0" stop-color="red" />
+            <stop offset="0.5" stop-color="rgb(255, 128, 255)" />
+            <stop offset="0.75" stop-color="yellow" />
+        </radialGradient>
+
+        <filter id="flood" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+            <feFlood flood-color="rgb(255, 128, 255)" />
+        </filter>
+
+        <filter id="diffuse-light" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+            <feDiffuseLighting lighting-color="rgb(255, 128, 255)">
+                <feDistantLight azimuth="100" elevation="100"/>
+            </feDiffuseLighting>
+        </filter>
+
+        <filter id="specular-light" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+            <feSpecularLighting surfaceScale="2" specularExponent="2" specularConstant="2" lighting-color="rgb(255, 128, 255)">
+                <fePointLight x="20" y="20" z="2"/>
+            </feSpecularLighting>
+        </filter>
+
+        <filter id="shadow" x="0" y="0" width="160%" height="160%">
+            <feDropShadow dx="50" dy="50" stdDeviation="0" flood-color="rgb(255, 128, 255)" flood-opacity="1" />
+        </filter>
+
+        <pattern id="pattern" patternUnits="userSpaceOnUse" x="20" y="0" width="50" height="50">
+           <rect x="5" y="5" width="30" height="30" fill="rgb(255, 128, 255)"/>
+        </pattern>
+    </defs>
+
+    <rect x="20" y="10" width="150" height="150" fill="url(#grad)" />
+
+    <rect x="200" y="10" width="150" height="150" fill="rgb(255, 128, 255)" />
+    <rect x="400" y="10" width="150" height="150" fill="rgb(255, 128, 255)" stroke="yellow" stroke-width="15" />
+
+    <rect x="20" y="200" width="150" height="150" filter="url(#flood)"/>
+    <rect x="200" y="200" width="150" height="150" filter="url(#diffuse-light)"/>
+    <rect x="400" y="200" width="150" height="150" filter="url(#specular-light)"/>
+
+    <rect x="20" y="400" width="150" height="150" fill="url(#pattern)"/>
+
+    <rect x="200" y="400" width="100" height="100" fill="yellow" filter="url(#shadow)"/>
+</svg>
+
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index b5a0741..c4facc4 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,39 @@
+2018-04-28  Simon Fraser  <simon.fraser@apple.com>
+
+        Fix color-filter to apply to SVG colors
+        https://bugs.webkit.org/show_bug.cgi?id=185113
+        rdar://problem/39665082
+
+        Reviewed by Dean Jackson.
+        
+        Convert SVG colors through color-filter operations for the places in SVG
+        that use color, namely fill and stroke, gradients, lighting colors and
+        drop-shadow.
+
+        Test: css3/color-filters/svg/color-filter-inline-svg.html
+
+        * rendering/svg/RenderSVGResourceGradient.cpp:
+        (WebCore::RenderSVGResourceGradient::applyResource):
+        * rendering/svg/RenderSVGResourceGradient.h:
+        * rendering/svg/RenderSVGResourceLinearGradient.cpp:
+        (WebCore::RenderSVGResourceLinearGradient::buildGradient const):
+        * rendering/svg/RenderSVGResourceLinearGradient.h:
+        * rendering/svg/RenderSVGResourceRadialGradient.cpp:
+        (WebCore::RenderSVGResourceRadialGradient::buildGradient const):
+        * rendering/svg/RenderSVGResourceRadialGradient.h:
+        * rendering/svg/RenderSVGResourceSolidColor.cpp:
+        (WebCore::RenderSVGResourceSolidColor::applyResource):
+        * svg/SVGFEDiffuseLightingElement.cpp:
+        (WebCore::SVGFEDiffuseLightingElement::setFilterEffectAttribute):
+        (WebCore::SVGFEDiffuseLightingElement::build):
+        * svg/SVGFEDropShadowElement.cpp:
+        (WebCore::SVGFEDropShadowElement::build):
+        * svg/SVGFEFloodElement.cpp:
+        (WebCore::SVGFEFloodElement::build):
+        * svg/SVGFESpecularLightingElement.cpp:
+        (WebCore::SVGFESpecularLightingElement::setFilterEffectAttribute):
+        (WebCore::SVGFESpecularLightingElement::build):
+
 2018-04-29  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         [CMake] Require GCC 6
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
index 0b5d9b6..9781c4e 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
@@ -125,7 +125,7 @@
 
     // Create gradient object
     if (!gradientData->gradient) {
-        buildGradient(gradientData.get());
+        buildGradient(gradientData.get(), style);
 
         // CG platforms will handle the gradient space transform for text after applying the
         // resource, so don't apply it here. For non-CG platforms, we want the text bounding
@@ -232,13 +232,14 @@
     context->restore();
 }
 
-void RenderSVGResourceGradient::addStops(GradientData* gradientData, const Vector<Gradient::ColorStop>& stops) const
+void RenderSVGResourceGradient::addStops(GradientData* gradientData, const Vector<Gradient::ColorStop>& stops, const RenderStyle& style) const
 {
     ASSERT(gradientData->gradient);
 
-    const Vector<Gradient::ColorStop>::const_iterator end = stops.end();
-    for (Vector<Gradient::ColorStop>::const_iterator it = stops.begin(); it != end; ++it)
-        gradientData->gradient->addColorStop(*it);
+    for (Gradient::ColorStop stop : stops) {
+        stop.color = style.colorByApplyingColorFilter(stop.color);
+        gradientData->gradient->addColorStop(stop);
+    }
 }
 
 GradientSpreadMethod RenderSVGResourceGradient::platformSpreadMethodFromSVGType(SVGSpreadMethodType method) const
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
index cc360f4..140c70e 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
@@ -56,12 +56,12 @@
 
     void element() const = delete;
 
-    void addStops(GradientData*, const Vector<Gradient::ColorStop>&) const;
+    void addStops(GradientData*, const Vector<Gradient::ColorStop>&, const RenderStyle&) const;
 
     virtual SVGUnitTypes::SVGUnitType gradientUnits() const = 0;
     virtual void calculateGradientTransform(AffineTransform&) = 0;
     virtual bool collectGradientAttributes() = 0;
-    virtual void buildGradient(GradientData*) const = 0;
+    virtual void buildGradient(GradientData*, const RenderStyle&) const = 0;
 
     GradientSpreadMethod platformSpreadMethodFromSVGType(SVGSpreadMethodType) const;
 
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp
index 457b20c..9dd3250 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp
@@ -50,11 +50,11 @@
     return SVGLengthContext::resolvePoint(&linearGradientElement(), attributes.gradientUnits(), attributes.x2(), attributes.y2());
 }
 
-void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData) const
+void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData, const RenderStyle& style) const
 {
     gradientData->gradient = Gradient::create(Gradient::LinearData { startPoint(m_attributes), endPoint(m_attributes) });
     gradientData->gradient->setSpreadMethod(platformSpreadMethodFromSVGType(m_attributes.spreadMethod()));
-    addStops(gradientData, m_attributes.stops());
+    addStops(gradientData, m_attributes.stops(), style);
 }
 
 }
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h
index ba2ab89..4b93c87 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h
@@ -39,7 +39,7 @@
     SVGUnitTypes::SVGUnitType gradientUnits() const override { return m_attributes.gradientUnits(); }
     void calculateGradientTransform(AffineTransform& transform) override { transform = m_attributes.gradientTransform(); }
     bool collectGradientAttributes() override;
-    void buildGradient(GradientData*) const override;
+    void buildGradient(GradientData*, const RenderStyle&) const override;
 
     FloatPoint startPoint(const LinearGradientAttributes&) const;
     FloatPoint endPoint(const LinearGradientAttributes&) const;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp
index 7af48c65..09a5cc2 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp
@@ -61,12 +61,12 @@
     return SVGLengthContext::resolveLength(&radialGradientElement(), attributes.gradientUnits(), attributes.fr());
 }
 
-void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData) const
+void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData, const RenderStyle& style) const
 {
     gradientData->gradient = Gradient::create(Gradient::RadialData { this->focalPoint(m_attributes), this->centerPoint(m_attributes), this->focalRadius(m_attributes), this->radius(m_attributes), 1 });
     gradientData->gradient->setSpreadMethod(platformSpreadMethodFromSVGType(m_attributes.spreadMethod()));
 
-    addStops(gradientData, m_attributes.stops());
+    addStops(gradientData, m_attributes.stops(), style);
 }
 
 }
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h
index fb3050b..809930c 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h
@@ -40,7 +40,7 @@
 
     SVGUnitTypes::SVGUnitType gradientUnits() const override { return m_attributes.gradientUnits(); }
     void calculateGradientTransform(AffineTransform& transform) override { transform = m_attributes.gradientTransform(); }
-    void buildGradient(GradientData*) const override;
+    void buildGradient(GradientData*, const RenderStyle&) const override;
 
     FloatPoint centerPoint(const RadialGradientAttributes&) const;
     FloatPoint focalPoint(const RadialGradientAttributes&) const;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
index 09a6e0c..6520c41 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp
@@ -46,7 +46,7 @@
             context->setAlpha(svgStyle.fillOpacity());
         else
             context->setAlpha(1);
-        context->setFillColor(m_color);
+        context->setFillColor(style.colorByApplyingColorFilter(m_color));
         if (!isRenderingMask)
             context->setFillRule(svgStyle.fillRule());
 
@@ -56,7 +56,7 @@
         // When rendering the mask for a RenderSVGResourceClipper, the stroke code path is never hit.
         ASSERT(!isRenderingMask);
         context->setAlpha(svgStyle.strokeOpacity());
-        context->setStrokeColor(m_color);
+        context->setStrokeColor(style.colorByApplyingColorFilter(m_color));
 
         SVGRenderSupport::applyStrokeStyleToContext(context, style, renderer);
 
diff --git a/Source/WebCore/svg/SVGFEDiffuseLightingElement.cpp b/Source/WebCore/svg/SVGFEDiffuseLightingElement.cpp
index 66c5dbb..3ea3b16 100644
--- a/Source/WebCore/svg/SVGFEDiffuseLightingElement.cpp
+++ b/Source/WebCore/svg/SVGFEDiffuseLightingElement.cpp
@@ -111,7 +111,8 @@
     if (attrName == SVGNames::lighting_colorAttr) {
         RenderObject* renderer = this->renderer();
         ASSERT(renderer);
-        return diffuseLighting->setLightingColor(renderer->style().svgStyle().lightingColor());
+        Color color = renderer->style().colorByApplyingColorFilter(renderer->style().svgStyle().lightingColor());
+        return diffuseLighting->setLightingColor(color);
     }
     if (attrName == SVGNames::surfaceScaleAttr)
         return diffuseLighting->setSurfaceScale(surfaceScale());
@@ -190,7 +191,7 @@
     if (!renderer)
         return nullptr;
 
-    const Color& color = renderer->style().svgStyle().lightingColor();
+    Color color = renderer->style().colorByApplyingColorFilter(renderer->style().svgStyle().lightingColor());
 
     RefPtr<FilterEffect> effect = FEDiffuseLighting::create(filter, color, surfaceScale(), diffuseConstant(), kernelUnitLengthX(), kernelUnitLengthY(), WTFMove(lightSource));
     effect->inputEffects().append(input1);
diff --git a/Source/WebCore/svg/SVGFEDropShadowElement.cpp b/Source/WebCore/svg/SVGFEDropShadowElement.cpp
index ed53a54..cc4bba1 100644
--- a/Source/WebCore/svg/SVGFEDropShadowElement.cpp
+++ b/Source/WebCore/svg/SVGFEDropShadowElement.cpp
@@ -133,7 +133,7 @@
 
     const SVGRenderStyle& svgStyle = renderer->style().svgStyle();
     
-    const Color& color = svgStyle.floodColor();
+    Color color = renderer->style().colorByApplyingColorFilter(svgStyle.floodColor());
     float opacity = svgStyle.floodOpacity();
 
     auto input1 = filterBuilder->getEffectById(in1());
diff --git a/Source/WebCore/svg/SVGFEFloodElement.cpp b/Source/WebCore/svg/SVGFEFloodElement.cpp
index 7f7e0d4..cfe642a 100644
--- a/Source/WebCore/svg/SVGFEFloodElement.cpp
+++ b/Source/WebCore/svg/SVGFEFloodElement.cpp
@@ -66,7 +66,7 @@
     
     const SVGRenderStyle& svgStyle = renderer->style().svgStyle();
 
-    const Color& color = svgStyle.floodColor();
+    Color color = renderer->style().colorByApplyingColorFilter(svgStyle.floodColor());
     float opacity = svgStyle.floodOpacity();
 
     return FEFlood::create(filter, color, opacity);
diff --git a/Source/WebCore/svg/SVGFESpecularLightingElement.cpp b/Source/WebCore/svg/SVGFESpecularLightingElement.cpp
index 57510cf..b0454c2 100644
--- a/Source/WebCore/svg/SVGFESpecularLightingElement.cpp
+++ b/Source/WebCore/svg/SVGFESpecularLightingElement.cpp
@@ -120,7 +120,8 @@
     if (attrName == SVGNames::lighting_colorAttr) {
         RenderObject* renderer = this->renderer();
         ASSERT(renderer);
-        return specularLighting->setLightingColor(renderer->style().svgStyle().lightingColor());
+        Color color = renderer->style().colorByApplyingColorFilter(renderer->style().svgStyle().lightingColor());
+        return specularLighting->setLightingColor(color);
     }
     if (attrName == SVGNames::surfaceScaleAttr)
         return specularLighting->setSurfaceScale(surfaceScale());
@@ -201,7 +202,7 @@
     if (!renderer)
         return nullptr;
     
-    const Color& color = renderer->style().svgStyle().lightingColor();
+    Color color = renderer->style().colorByApplyingColorFilter(renderer->style().svgStyle().lightingColor());
 
     RefPtr<FilterEffect> effect = FESpecularLighting::create(filter, color, surfaceScale(), specularConstant(), specularExponent(), kernelUnitLengthX(), kernelUnitLengthY(), WTFMove(lightSource));
     effect->inputEffects().append(input1);