From 5eb5ab62f15afd0aeca4a782baa1157ed20813fe Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 21 Feb 2024 04:21:52 -0800 Subject: [PATCH] Cherry-pick 275091@main (cfa8125ddf7c). https://bugs.webkit.org/show_bug.cgi?id=268537 Regression(251234@main): [Cairo][GTK][WPE] Darker output of SVG with filters fediffuselighting https://bugs.webkit.org/show_bug.cgi?id=268537 Reviewed by Said Abou-Hallawa and Nikolas Zimmermann. Turn off the support for linearRGB color space in case of Cairo (251234@main) causes, that SVG with filter, where linearRGB as inputs is demanded, generates darker output. The SVG spec says that SourceGraphic has to be in linearRGB color space: https://www.w3.org/TR/filter-effects-1/#attr-valuedef-in-sourcegraphic In case of Cairo (which operates in SRGB color space) the image source (SourceGraphic) should be created in SRGB and before passing it to filters, it should be transformed to linearRGB color space. * LayoutTests/TestExpectations: * LayoutTests/platform/glib/TestExpectations: Remove some tests which pass with this change * LayoutTests/svg/filters/feConvolveMatrix-clipped.svg: * LayoutTests/svg/filters/feGaussianBlur-clipped.svg: * LayoutTests/fast/gradients/conic-gradient-extended-stops.html: Add possible differences in outputs * Source/WebCore/platform/graphics/ImageBuffer.cpp: (WebCore::ImageBuffer::filteredNativeImage): Pass color space to endDrawSourceImage * Source/WebCore/platform/graphics/filters/FEDropShadow.h: Force to use SRGB as operating color space for DropShadow in case of Cairo. * Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.cpp: (WebCore::FilterImageTargetSwitcher::endClipAndDrawSourceImage): (WebCore::FilterImageTargetSwitcher::endDrawSourceImage): Before applying all filter, the source image has to be translated to requested color space (only valid for Cairo). * Source/WebCore/platform/graphics/filters/FilterTargetSwitcher.h: * Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.h: * Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.h: Added color space as additional parameter. * Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.cpp: (WebCore::FilterStyleTargetSwitcher::endDrawSourceImage): WebCore::FilterStyleTargetSwitcher::endDrawSourceImage does not use color space so just ignore it * Source/WebCore/rendering/RenderLayerFilters.cpp: (WebCore::RenderLayerFilters::applyFilterEffect): Just pass DestinationColorSpace::SRGB() to endClipAndDrawSourceImage. * Source/WebCore/rendering/svg/legacy/LegacyRenderSVGResourceFilter.cpp: (WebCore::LegacyRenderSVGResourceFilter::applyResource): In case of Cairo, the sourceImage has to be created with sRGB color space, because Cairo operates in sRGB. The linearRGB color space will be passed to TargetSwitcher in WebCore::LegacyRenderSVGResourceFilter::postApplyResource and the sourceImage will be transformed to linearRGB before all filter applying. (WebCore::LegacyRenderSVGResourceFilter::postApplyResource): Before applying all filter, the source image has to be translated to requested color space. * Source/WebCore/svg/graphics/filters/SVGFilter.cpp: (WebCore::buildFilterEffectsGraph): Create SourceGraphic and SourceAlpha with LinearRGB color space if color-interpolation_filter attribute of the Filter has LinearRGB value (only in case of Cairo). Canonical link: https://commits.webkit.org/275091@main Canonical link: https://commits.webkit.org/274313.44@webkitglib/2.44 --- LayoutTests/TestExpectations | 1 - .../gradients/conic-gradient-extended-stops.html | 1 + LayoutTests/platform/glib/TestExpectations | 6 ------ .../svg/filters/feConvolveMatrix-clipped.svg | 1 + .../svg/filters/feGaussianBlur-clipped.svg | 1 + Source/WTF/wtf/PlatformEnable.h | 2 +- Source/WebCore/platform/graphics/ImageBuffer.cpp | 2 +- .../platform/graphics/filters/FEDropShadow.h | 4 ++++ .../filters/FilterImageTargetSwitcher.cpp | 15 ++++++++++++--- .../graphics/filters/FilterImageTargetSwitcher.h | 4 ++-- .../filters/FilterStyleTargetSwitcher.cpp | 2 +- .../graphics/filters/FilterStyleTargetSwitcher.h | 4 ++-- .../graphics/filters/FilterTargetSwitcher.h | 4 ++-- Source/WebCore/rendering/RenderLayerFilters.cpp | 2 +- .../svg/legacy/LegacyRenderSVGResourceFilter.cpp | 8 ++++---- Source/WebCore/svg/graphics/filters/SVGFilter.cpp | 3 ++- 16 files changed, 35 insertions(+), 25 deletions(-) diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations index 218170839b0a..554d816c1c54 100644 --- a/LayoutTests/TestExpectations +++ b/LayoutTests/TestExpectations @@ -5333,7 +5333,6 @@ imported/w3c/web-platform-tests/css/filter-effects/tainting-feoffset-002.html [ imported/w3c/web-platform-tests/css/filter-effects/tainting-fespecularlighting-002.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/filter-effects/tainting-fespecularlighting-003.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/filter-effects/tainting-fetile-002.html [ ImageOnlyFailure ] -imported/w3c/web-platform-tests/css/filter-effects/backdrop-filter-edge-behavior.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/filter-effects/backdrop-filter-reference-filter.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/filter-effects/effect-reference-feimage-004.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/filter-effects/filter-function/filter-function-001.html [ ImageOnlyFailure ] diff --git a/LayoutTests/fast/gradients/conic-gradient-extended-stops.html b/LayoutTests/fast/gradients/conic-gradient-extended-stops.html index 78df2763f468..fe9375b9bbc7 100644 --- a/LayoutTests/fast/gradients/conic-gradient-extended-stops.html +++ b/LayoutTests/fast/gradients/conic-gradient-extended-stops.html @@ -36,6 +36,7 @@ + diff --git a/LayoutTests/platform/glib/TestExpectations b/LayoutTests/platform/glib/TestExpectations index 4c7b6ca502c9..052b26e81cdb 100644 --- a/LayoutTests/platform/glib/TestExpectations +++ b/LayoutTests/platform/glib/TestExpectations @@ -1675,7 +1675,6 @@ webkit.org/b/240934 imported/w3c/web-platform-tests/css/filter-effects/effect-re webkit.org/b/240934 imported/w3c/web-platform-tests/css/filter-effects/root-element-with-opacity-filter-001.html [ ImageOnlyFailure ] webkit.org/b/264583 imported/w3c/web-platform-tests/css/filter-effects/css-filters-animation-saturate.html [ ImageOnlyFailure ] -webkit.org/b/264583 imported/w3c/web-platform-tests/css/filter-effects/repaint-added-backdrop-filter.html [ ImageOnlyFailure ] webkit.org/b/264584 imported/w3c/web-platform-tests/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Failure ] webkit.org/b/264584 imported/w3c/web-platform-tests/fetch/metadata/generated/css-font-face.sub.tentative.html [ Failure ] webkit.org/b/264584 imported/w3c/web-platform-tests/fetch/private-network-access/fetch.https.window.html [ Failure ] @@ -3290,16 +3289,11 @@ fast/text/line-break-with-locale.html [ ImageOnlyFailure ] webkit.org/b/225423 fast/canvas/canvas-composite-text-alpha.html [ Failure ] # Non-sRGB color spaces are not currently supported by the glib ports. -css3/color-filters/svg/color-filter-inline-svg.html [ ImageOnlyFailure ] -css3/filters/reference-filter-color-space.html [ ImageOnlyFailure ] fast/canvas/canvas-color-space-display-p3.html [ Skip ] fast/canvas/canvas-color-space-display-p3-ImageData.html [ Skip ] imported/w3c/web-platform-tests/html/canvas/element/wide-gamut-canvas/ [ Skip ] imported/w3c/web-platform-tests/html/canvas/element/manual/wide-gamut-canvas/ [ Skip ] imported/w3c/web-platform-tests/html/canvas/offscreen/wide-gamut-canvas/ [ Skip ] -svg/filters/feCompositeOpaque.html [ ImageOnlyFailure ] -svg/filters/feDiffuseLighting-bottomRightPixel.html [ ImageOnlyFailure ] -svg/filters/feDisplacementMap-filterUnits.svg [ ImageOnlyFailure ] webkit.org/b/254415 fast/canvas/canvas-drawImage-hdr-video.html [ Failure ] diff --git a/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg b/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg index f5cf7a8493cc..de288433e8df 100644 --- a/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg +++ b/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg @@ -1,4 +1,5 @@ + diff --git a/LayoutTests/svg/filters/feGaussianBlur-clipped.svg b/LayoutTests/svg/filters/feGaussianBlur-clipped.svg index b25528af46ed..a6523ceda440 100644 --- a/LayoutTests/svg/filters/feGaussianBlur-clipped.svg +++ b/LayoutTests/svg/filters/feGaussianBlur-clipped.svg @@ -1,4 +1,5 @@ + diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h index 81322cbfa8b4..8460fc0b744e 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h @@ -209,7 +209,7 @@ #endif #if !defined(ENABLE_DESTINATION_COLOR_SPACE_LINEAR_SRGB) -#define ENABLE_DESTINATION_COLOR_SPACE_LINEAR_SRGB 0 +#define ENABLE_DESTINATION_COLOR_SPACE_LINEAR_SRGB 1 #endif #if !defined(ENABLE_DRAG_SUPPORT) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.cpp b/Source/WebCore/platform/graphics/ImageBuffer.cpp index 780fdc07b5bd..d7723ad2c1bf 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.cpp +++ b/Source/WebCore/platform/graphics/ImageBuffer.cpp @@ -350,7 +350,7 @@ RefPtr ImageBuffer::filteredNativeImage(Filter& filter, FunctionendDrawSourceImage(context()); + targetSwitcher->endDrawSourceImage(context(), colorSpace()); return copyImageBufferToNativeImage(*this, CopyBackingStore, PreserveResolution::No); } diff --git a/Source/WebCore/platform/graphics/filters/FEDropShadow.h b/Source/WebCore/platform/graphics/filters/FEDropShadow.h index ea7f3c31b6d7..8c609550b5be 100644 --- a/Source/WebCore/platform/graphics/filters/FEDropShadow.h +++ b/Source/WebCore/platform/graphics/filters/FEDropShadow.h @@ -51,6 +51,10 @@ class FEDropShadow : public FilterEffect { static IntOutsets calculateOutsets(const FloatSize& offset, const FloatSize& stdDeviation); +#if USE(CAIRO) + void setOperatingColorSpace(const DestinationColorSpace&) override { } +#endif + private: FEDropShadow(float stdX, float stdY, float dx, float dy, const Color& shadowColor, float shadowOpacity, DestinationColorSpace); diff --git a/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.cpp b/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.cpp index b31b5394af3f..932961dcc717 100644 --- a/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.cpp +++ b/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.cpp @@ -65,20 +65,29 @@ void FilterImageTargetSwitcher::beginClipAndDrawSourceImage(GraphicsContext& des } } -void FilterImageTargetSwitcher::endClipAndDrawSourceImage(GraphicsContext& destinationContext) +void FilterImageTargetSwitcher::endClipAndDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace& colorSpace) { if (auto* context = drawingContext(destinationContext)) context->restore(); - endDrawSourceImage(destinationContext); + endDrawSourceImage(destinationContext, colorSpace); } -void FilterImageTargetSwitcher::endDrawSourceImage(GraphicsContext& destinationContext) +void FilterImageTargetSwitcher::endDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace& colorSpace) { if (!m_filter) return; FilterResults results; +#if USE(CAIRO) + // Cairo operates in SRGB which is why the SourceImage initially is in SRGB color space, + // but before applying all filters it has to be transformed to LinearRGB to comply with + // specification (https://www.w3.org/TR/filter-effects-1/#attr-valuedef-in-sourcegraphic). + if (m_sourceImage) + m_sourceImage->transformToColorSpace(colorSpace); +#else + UNUSED_PARAM(colorSpace); +#endif destinationContext.drawFilteredImageBuffer(m_sourceImage.get(), m_sourceImageRect, Ref { *m_filter }, m_results ? *m_results : results); } diff --git a/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.h b/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.h index 4ec73a35c5b2..d5a4068b935e 100644 --- a/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.h +++ b/Source/WebCore/platform/graphics/filters/FilterImageTargetSwitcher.h @@ -42,10 +42,10 @@ class FilterImageTargetSwitcher final : public FilterTargetSwitcher { bool hasSourceImage() const override { return m_sourceImage; } void beginClipAndDrawSourceImage(GraphicsContext& destinationContext, const FloatRect& repaintRect, const FloatRect& clipRect) override; - void endClipAndDrawSourceImage(GraphicsContext& destinationContext) override; + void endClipAndDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace&) override; void beginDrawSourceImage(GraphicsContext&) override { } - void endDrawSourceImage(GraphicsContext& destinationContext) override; + void endDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace&) override; RefPtr m_sourceImage; FloatRect m_sourceImageRect; diff --git a/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.cpp b/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.cpp index ab8324616bb7..a599a2eaca38 100644 --- a/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.cpp +++ b/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.cpp @@ -57,7 +57,7 @@ void FilterStyleTargetSwitcher::beginDrawSourceImage(GraphicsContext& destinatio } } -void FilterStyleTargetSwitcher::endDrawSourceImage(GraphicsContext& destinationContext) +void FilterStyleTargetSwitcher::endDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace&) { for ([[maybe_unused]] auto& filterStyle : makeReversedRange(m_filterStyles)) { destinationContext.endTransparencyLayer(); diff --git a/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.h b/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.h index dd732788b24d..7a4eaa1c89b2 100644 --- a/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.h +++ b/Source/WebCore/platform/graphics/filters/FilterStyleTargetSwitcher.h @@ -37,10 +37,10 @@ class FilterStyleTargetSwitcher : public FilterTargetSwitcher { private: void beginClipAndDrawSourceImage(GraphicsContext& destinationContext, const FloatRect& repaintRect, const FloatRect& clipRect) override; - void endClipAndDrawSourceImage(GraphicsContext& destinationContext) override { endDrawSourceImage(destinationContext); } + void endClipAndDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace& colorSpace) override { endDrawSourceImage(destinationContext, colorSpace); } void beginDrawSourceImage(GraphicsContext& destinationContext) override; - void endDrawSourceImage(GraphicsContext& destinationContext) override; + void endDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace&) override; FilterStyleVector m_filterStyles; }; diff --git a/Source/WebCore/platform/graphics/filters/FilterTargetSwitcher.h b/Source/WebCore/platform/graphics/filters/FilterTargetSwitcher.h index caa53d52ddc2..16e98edee793 100644 --- a/Source/WebCore/platform/graphics/filters/FilterTargetSwitcher.h +++ b/Source/WebCore/platform/graphics/filters/FilterTargetSwitcher.h @@ -47,10 +47,10 @@ class FilterTargetSwitcher { virtual bool hasSourceImage() const { return false; } virtual void beginClipAndDrawSourceImage(GraphicsContext& destinationContext, const FloatRect& repaintRect, const FloatRect& clipRect) = 0; - virtual void endClipAndDrawSourceImage(GraphicsContext& destinationContext) = 0; + virtual void endClipAndDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace&) = 0; virtual void beginDrawSourceImage(GraphicsContext& destinationContext) = 0; - virtual void endDrawSourceImage(GraphicsContext& destinationContext) = 0; + virtual void endDrawSourceImage(GraphicsContext& destinationContext, const DestinationColorSpace&) = 0; protected: FilterTargetSwitcher(Filter&); diff --git a/Source/WebCore/rendering/RenderLayerFilters.cpp b/Source/WebCore/rendering/RenderLayerFilters.cpp index fb77f6de4634..ba4a5017cb26 100644 --- a/Source/WebCore/rendering/RenderLayerFilters.cpp +++ b/Source/WebCore/rendering/RenderLayerFilters.cpp @@ -205,7 +205,7 @@ void RenderLayerFilters::applyFilterEffect(GraphicsContext& destinationContext) LOG_WITH_STREAM(Filters, stream << "\nRenderLayerFilters " << this << " applyFilterEffect"); ASSERT(m_targetSwitcher); - m_targetSwitcher->endClipAndDrawSourceImage(destinationContext); + m_targetSwitcher->endClipAndDrawSourceImage(destinationContext, DestinationColorSpace::SRGB()); LOG_WITH_STREAM(Filters, stream << "RenderLayerFilters " << this << " applyFilterEffect done\n"); } diff --git a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGResourceFilter.cpp index a8dec8e0035e..8467ef8aaed0 100644 --- a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGResourceFilter.cpp +++ b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGResourceFilter.cpp @@ -139,10 +139,10 @@ bool LegacyRenderSVGResourceFilter::applyResource(RenderElement& renderer, const filterData->filter->clampFilterRegionIfNeeded(); -#if ENABLE(DESTINATION_COLOR_SPACE_LINEAR_SRGB) - auto colorSpace = DestinationColorSpace::LinearSRGB(); -#else +#if USE(CAIRO) auto colorSpace = DestinationColorSpace::SRGB(); +#else + auto colorSpace = DestinationColorSpace::LinearSRGB(); #endif auto& results = filterData->filter->ensureResults([&]() { @@ -215,7 +215,7 @@ void LegacyRenderSVGResourceFilter::postApplyResource(RenderElement& renderer, G if (filterData.targetSwitcher) { filterData.state = FilterData::Built; - filterData.targetSwitcher->endDrawSourceImage(*context); + filterData.targetSwitcher->endDrawSourceImage(*context, DestinationColorSpace::LinearSRGB()); } LOG_WITH_STREAM(Filters, stream << "LegacyRenderSVGResourceFilter " << this << " postApplyResource done\n"); diff --git a/Source/WebCore/svg/graphics/filters/SVGFilter.cpp b/Source/WebCore/svg/graphics/filters/SVGFilter.cpp index a92080848c49..0d80c95a6a70 100644 --- a/Source/WebCore/svg/graphics/filters/SVGFilter.cpp +++ b/Source/WebCore/svg/graphics/filters/SVGFilter.cpp @@ -99,7 +99,8 @@ static std::optional> if (filterElement.countChildNodes() > maxCountChildNodes) return std::nullopt; - SVGFilterEffectsGraph graph(SourceGraphic::create(), SourceAlpha::create()); + const auto colorSpace = filterElement.colorInterpolation() == ColorInterpolation::LinearRGB ? DestinationColorSpace::LinearSRGB() : DestinationColorSpace::SRGB(); + SVGFilterEffectsGraph graph(SourceGraphic::create(colorSpace), SourceAlpha::create(colorSpace)); FilterEffectGeometryMap effectGeometryMap; for (auto& effectElement : childrenOfType(filterElement)) {