Make color-filter transform gradient colors
https://bugs.webkit.org/show_bug.cgi?id=185080
Reviewed by Zalan Bujtas.
Source/WebCore:
In CSSGradientValue::computeStops(), transform the color of each gradient color
stop through the color filter. Having a color filter makes the gradient uncacheable.
Color filters can add alpha, so we also have to fix up CSSGradientValue::knownToBeOpaque()
to take a RenderStyle and convert the colors before testing opaqueness. Clean up some related
functions to take const RenderStyle&.
Test: css3/color-filters/color-filter-gradients.html
* css/CSSCrossfadeValue.cpp:
(WebCore::subimageKnownToBeOpaque):
* css/CSSFilterImageValue.cpp:
(WebCore::CSSFilterImageValue::knownToBeOpaque const):
* css/CSSFilterImageValue.h:
* css/CSSGradientValue.cpp:
(WebCore::CSSGradientValue::image):
(WebCore::CSSGradientValue::computeStops):
(WebCore::CSSGradientValue::knownToBeOpaque const):
(WebCore::CSSLinearGradientValue::createGradient):
(WebCore::CSSRadialGradientValue::createGradient):
* css/CSSGradientValue.h:
* css/CSSImageGeneratorValue.cpp:
(WebCore::CSSImageGeneratorValue::knownToBeOpaque const):
* css/CSSImageValue.cpp:
(WebCore::CSSImageValue::knownToBeOpaque const):
* css/CSSImageValue.h:
LayoutTests:
* css3/color-filters/color-filter-gradients-expected.html: Added.
* css3/color-filters/color-filter-gradients.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231105 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index e65c3c2..5e5d3b0 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,5 +1,15 @@
2018-04-27 Simon Fraser <simon.fraser@apple.com>
+ Make color-filter transform gradient colors
+ https://bugs.webkit.org/show_bug.cgi?id=185080
+
+ Reviewed by Zalan Bujtas.
+
+ * css3/color-filters/color-filter-gradients-expected.html: Added.
+ * css3/color-filters/color-filter-gradients.html: Added.
+
+2018-04-27 Simon Fraser <simon.fraser@apple.com>
+
Disable color-filter tests on Windows for now
https://bugs.webkit.org/show_bug.cgi?id=185076
diff --git a/LayoutTests/css3/color-filters/color-filter-gradients-expected.html b/LayoutTests/css3/color-filters/color-filter-gradients-expected.html
new file mode 100644
index 0000000..39a7963
--- /dev/null
+++ b/LayoutTests/css3/color-filters/color-filter-gradients-expected.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Test: color-filter reference</title>
+ <link rel="author" title="Apple" href="http://www.apple.com/">
+
+ <style type="text/css">
+ .test
+ {
+ width: 200px;
+ height: 200px;
+ margin: 10px;
+ float: left;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="test" style="background-image: linear-gradient(blue, red);"></div>
+ <div class="test" style="background-image: radial-gradient(blue, red);"></div>
+ <div class="test" style="background-image: repeating-linear-gradient(blue, red 50px);"></div>
+ <div class="test" style="background-image: repeating-radial-gradient(blue, red 50px);"></div>
+ </body>
+</html>
diff --git a/LayoutTests/css3/color-filters/color-filter-gradients.html b/LayoutTests/css3/color-filters/color-filter-gradients.html
new file mode 100644
index 0000000..4e1cae9
--- /dev/null
+++ b/LayoutTests/css3/color-filters/color-filter-gradients.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS Test: color-filter affects gradients</title>
+ <link rel="author" title="Apple" href="http://www.apple.com/">
+ <link rel="match" href="color-filter-grayscale-expected.html">
+
+ <meta name="assert" content="color-filter affects gradients">
+ <style type="text/css">
+ .test
+ {
+ width: 200px;
+ height: 200px;
+ margin: 10px;
+ float: left;
+ color-filter: invert();
+ }
+ </style>
+ <script>
+ if (window.internals)
+ internals.settings.setColorFilterEnabled(true);
+ </script>
+ </head>
+ <body>
+ <div class="test" style="background-image: linear-gradient(yellow, cyan);"></div>
+ <div class="test" style="background-image: radial-gradient(yellow, cyan);"></div>
+ <div class="test" style="background-image: repeating-linear-gradient(yellow, cyan 50px);"></div>
+ <div class="test" style="background-image: repeating-radial-gradient(yellow, cyan 50px);"></div>
+ </body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index c98d01b..05ebb31 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,37 @@
+2018-04-27 Simon Fraser <simon.fraser@apple.com>
+
+ Make color-filter transform gradient colors
+ https://bugs.webkit.org/show_bug.cgi?id=185080
+
+ Reviewed by Zalan Bujtas.
+
+ In CSSGradientValue::computeStops(), transform the color of each gradient color
+ stop through the color filter. Having a color filter makes the gradient uncacheable.
+
+ Color filters can add alpha, so we also have to fix up CSSGradientValue::knownToBeOpaque()
+ to take a RenderStyle and convert the colors before testing opaqueness. Clean up some related
+ functions to take const RenderStyle&.
+
+ Test: css3/color-filters/color-filter-gradients.html
+
+ * css/CSSCrossfadeValue.cpp:
+ (WebCore::subimageKnownToBeOpaque):
+ * css/CSSFilterImageValue.cpp:
+ (WebCore::CSSFilterImageValue::knownToBeOpaque const):
+ * css/CSSFilterImageValue.h:
+ * css/CSSGradientValue.cpp:
+ (WebCore::CSSGradientValue::image):
+ (WebCore::CSSGradientValue::computeStops):
+ (WebCore::CSSGradientValue::knownToBeOpaque const):
+ (WebCore::CSSLinearGradientValue::createGradient):
+ (WebCore::CSSRadialGradientValue::createGradient):
+ * css/CSSGradientValue.h:
+ * css/CSSImageGeneratorValue.cpp:
+ (WebCore::CSSImageGeneratorValue::knownToBeOpaque const):
+ * css/CSSImageValue.cpp:
+ (WebCore::CSSImageValue::knownToBeOpaque const):
+ * css/CSSImageValue.h:
+
2018-04-26 Simon Fraser <simon.fraser@apple.com>
Fix color-filter to apply to text decorations
diff --git a/Source/WebCore/css/CSSCrossfadeValue.cpp b/Source/WebCore/css/CSSCrossfadeValue.cpp
index 9eb6f0f..172c945 100644
--- a/Source/WebCore/css/CSSCrossfadeValue.cpp
+++ b/Source/WebCore/css/CSSCrossfadeValue.cpp
@@ -46,7 +46,7 @@
static bool subimageKnownToBeOpaque(const CSSValue& value, const RenderElement& renderer)
{
if (is<CSSImageValue>(value))
- return downcast<CSSImageValue>(value).knownToBeOpaque(&renderer);
+ return downcast<CSSImageValue>(value).knownToBeOpaque(renderer);
if (is<CSSImageGeneratorValue>(value))
return downcast<CSSImageGeneratorValue>(value).knownToBeOpaque(renderer);
diff --git a/Source/WebCore/css/CSSFilterImageValue.cpp b/Source/WebCore/css/CSSFilterImageValue.cpp
index eaab703..6acf744 100644
--- a/Source/WebCore/css/CSSFilterImageValue.cpp
+++ b/Source/WebCore/css/CSSFilterImageValue.cpp
@@ -76,7 +76,7 @@
return CSSImageGeneratorValue::subimageIsPending(m_imageValue);
}
-bool CSSFilterImageValue::knownToBeOpaque(const RenderElement*) const
+bool CSSFilterImageValue::knownToBeOpaque(const RenderElement&) const
{
return false;
}
diff --git a/Source/WebCore/css/CSSFilterImageValue.h b/Source/WebCore/css/CSSFilterImageValue.h
index 3ffc4f2..8f1c999 100644
--- a/Source/WebCore/css/CSSFilterImageValue.h
+++ b/Source/WebCore/css/CSSFilterImageValue.h
@@ -58,7 +58,7 @@
FloatSize fixedSize(const RenderElement*);
bool isPending() const;
- bool knownToBeOpaque(const RenderElement*) const;
+ bool knownToBeOpaque(const RenderElement&) const;
void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&);
diff --git a/Source/WebCore/css/CSSGradientValue.cpp b/Source/WebCore/css/CSSGradientValue.cpp
index eef295b..171d4726 100644
--- a/Source/WebCore/css/CSSGradientValue.cpp
+++ b/Source/WebCore/css/CSSGradientValue.cpp
@@ -52,7 +52,7 @@
{
if (size.isEmpty())
return nullptr;
- bool cacheable = isCacheable();
+ bool cacheable = isCacheable() && !renderer.style().hasColorFilter();
if (cacheable) {
if (!clients().contains(&renderer))
return nullptr;
@@ -225,7 +225,7 @@
};
template<typename GradientAdapter>
-Gradient::ColorStopVector CSSGradientValue::computeStops(GradientAdapter& gradient, const CSSToLengthConversionData& conversionData, float maxLengthForRepeat)
+Gradient::ColorStopVector CSSGradientValue::computeStops(GradientAdapter& gradient, const CSSToLengthConversionData& conversionData, const RenderStyle& style, float maxLengthForRepeat)
{
if (m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient) {
sortStopsIfNeeded();
@@ -240,7 +240,10 @@
else
offset = stop.m_position->floatValue(CSSPrimitiveValue::CSS_NUMBER);
- result.uncheckedAppend({ offset, stop.m_resolvedColor });
+ Color color = stop.m_resolvedColor;
+ if (style.hasColorFilter())
+ style.colorFilter().transformColor(color);
+ result.uncheckedAppend({ offset, color });
}
return result;
@@ -259,7 +262,12 @@
auto& stop = m_stops[i];
stops[i].isMidpoint = stop.isMidpoint;
- stops[i].color = stop.m_resolvedColor;
+
+ Color color = stop.m_resolvedColor;
+ if (style.hasColorFilter())
+ style.colorFilter().transformColor(color);
+
+ stops[i].color = color;
if (stop.m_position) {
auto& positionValue = *stop.m_position;
@@ -569,9 +577,18 @@
return true;
}
-bool CSSGradientValue::knownToBeOpaque() const
+bool CSSGradientValue::knownToBeOpaque(const RenderElement& renderer) const
{
+ bool hasColorFilter = renderer.style().hasColorFilter();
+
for (auto& stop : m_stops) {
+ if (hasColorFilter) {
+ Color stopColor = stop.m_resolvedColor;
+ renderer.style().colorFilter().transformColor(stopColor);
+ if (!stopColor.isOpaque())
+ return false;
+ }
+
if (!stop.m_resolvedColor.isOpaque())
return false;
}
@@ -814,7 +831,7 @@
Gradient::LinearData data { firstPoint, secondPoint };
LinearGradientAdapter adapter { data };
- auto stops = computeStops(adapter, conversionData, 1);
+ auto stops = computeStops(adapter, conversionData, renderer.style(), 1);
auto gradient = Gradient::create(WTFMove(data));
gradient->setSortedColorStops(WTFMove(stops));
@@ -1231,7 +1248,7 @@
Gradient::RadialData data { firstPoint, secondPoint, firstRadius, secondRadius, aspectRatio };
RadialGradientAdapter adapter { data };
- auto stops = computeStops(adapter, conversionData, maxExtent);
+ auto stops = computeStops(adapter, conversionData, renderer.style(), maxExtent);
auto gradient = Gradient::create(WTFMove(data));
gradient->setSortedColorStops(WTFMove(stops));
diff --git a/Source/WebCore/css/CSSGradientValue.h b/Source/WebCore/css/CSSGradientValue.h
index 9cb03f4..68f8240 100644
--- a/Source/WebCore/css/CSSGradientValue.h
+++ b/Source/WebCore/css/CSSGradientValue.h
@@ -82,7 +82,7 @@
FloatSize fixedSize(const RenderElement&) const { return FloatSize(); }
bool isPending() const { return false; }
- bool knownToBeOpaque() const;
+ bool knownToBeOpaque(const RenderElement&) const;
void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&) { }
Ref<CSSGradientValue> gradientWithStylesResolved(const StyleResolver&);
@@ -110,7 +110,7 @@
}
template<typename GradientAdapter>
- Gradient::ColorStopVector computeStops(GradientAdapter&, const CSSToLengthConversionData&, float maxLengthForRepeat);
+ Gradient::ColorStopVector computeStops(GradientAdapter&, const CSSToLengthConversionData&, const RenderStyle&, float maxLengthForRepeat);
// Resolve points/radii to front end values.
FloatPoint computeEndPoint(CSSPrimitiveValue*, CSSPrimitiveValue*, const CSSToLengthConversionData&, const FloatSize&);
diff --git a/Source/WebCore/css/CSSImageGeneratorValue.cpp b/Source/WebCore/css/CSSImageGeneratorValue.cpp
index a7e664c..7a8e19f 100644
--- a/Source/WebCore/css/CSSImageGeneratorValue.cpp
+++ b/Source/WebCore/css/CSSImageGeneratorValue.cpp
@@ -233,13 +233,13 @@
case NamedImageClass:
return false;
case FilterImageClass:
- return downcast<CSSFilterImageValue>(*this).knownToBeOpaque(&renderer);
+ return downcast<CSSFilterImageValue>(*this).knownToBeOpaque(renderer);
case LinearGradientClass:
- return downcast<CSSLinearGradientValue>(*this).knownToBeOpaque();
+ return downcast<CSSLinearGradientValue>(*this).knownToBeOpaque(renderer);
case RadialGradientClass:
- return downcast<CSSRadialGradientValue>(*this).knownToBeOpaque();
+ return downcast<CSSRadialGradientValue>(*this).knownToBeOpaque(renderer);
case ConicGradientClass:
- return downcast<CSSConicGradientValue>(*this).knownToBeOpaque();
+ return downcast<CSSConicGradientValue>(*this).knownToBeOpaque(renderer);
default:
ASSERT_NOT_REACHED();
}
diff --git a/Source/WebCore/css/CSSImageValue.cpp b/Source/WebCore/css/CSSImageValue.cpp
index c191ecc..4ea4114 100644
--- a/Source/WebCore/css/CSSImageValue.cpp
+++ b/Source/WebCore/css/CSSImageValue.cpp
@@ -100,11 +100,11 @@
return DeprecatedCSSOMPrimitiveValue::create(CSSPrimitiveValue::create(m_url, CSSPrimitiveValue::CSS_URI), styleDeclaration);
}
-bool CSSImageValue::knownToBeOpaque(const RenderElement* renderer) const
+bool CSSImageValue::knownToBeOpaque(const RenderElement& renderer) const
{
if (!m_cachedImage)
return false;
- return m_cachedImage->currentFrameKnownToBeOpaque(renderer);
+ return m_cachedImage->currentFrameKnownToBeOpaque(&renderer);
}
} // namespace WebCore
diff --git a/Source/WebCore/css/CSSImageValue.h b/Source/WebCore/css/CSSImageValue.h
index 3ab5599..76f94df 100644
--- a/Source/WebCore/css/CSSImageValue.h
+++ b/Source/WebCore/css/CSSImageValue.h
@@ -54,7 +54,7 @@
bool equals(const CSSImageValue&) const;
- bool knownToBeOpaque(const RenderElement*) const;
+ bool knownToBeOpaque(const RenderElement&) const;
void setInitiator(const AtomicString& name) { m_initiatorName = name; }