Title: [286526] trunk
Revision
286526
Author
[email protected]
Date
2021-12-03 22:12:25 -0800 (Fri, 03 Dec 2021)

Log Message

[GPU Process] (REGRESSION r285597): Fix SVGFilter clamping calculation
https://bugs.webkit.org/show_bug.cgi?id=233843

Reviewed by Simon Fraser.

Source/WebCore:

In this patch:

1. lastEffect() is made virtual function of Filter and it's already
   implemented as non-virtual function in both CSSFilter and SVGFilter.

2. The clamping calculations for SVGFilter and CSSFilter are merged in
   one function called Filter::clampFilterRegionIfNeeded(). This merge
   makes the new function is the only caller to FilterEffect::maxEffectRect().

3. Remove FilterEffect::maxEffectRect() . It can be calculated by clipping
   the FilterEffect::filterPrimitiveSubregion() to filterRegion() and then
   scaling the result by filterScale().

4. In RenderSVGResourceFilter::applyResource() we need to pass the non-
   scaled drawingRegion to ImageBuffer::sizeNeedsClamping() because this
   function starts by scaling the argument 'size' by the argument 'scale'.
   So we were doubling the scaling by passing 'absoluteDrawingRegion'

5. SVGRenderingContext::createImageBuffer() needs to use ImageBuffer::
   sizeNeedsClamping() instead of using ImageBuffer::clampedSize(). The
   former function clamps the size to the MaxClampedArea. But the later
   function shrinks the size to { MaxClampedLength, MaxClampedLength }.
   When calling createImageBuffer() from RenderSVGResourceFilter::
   applyResource() we do not expect any further clamping. But if we pass
   a size with a side  greater than MaxClampedLength to clampedSize(),
   it  will be clamped even if the area is less than MaxClampedArea. And
   for filters we clamp to the area.

* platform/graphics/filters/Filter.cpp:
(WebCore::Filter::clampFilterRegionIfNeeded):
* platform/graphics/filters/Filter.h:
* platform/graphics/filters/FilterEffect.cpp:
(WebCore::FilterEffect::determineFilterPrimitiveSubregion):
(WebCore::FilterEffect::apply):
* platform/graphics/filters/FilterEffect.h:
(WebCore::FilterEffect::maxEffectRect const): Deleted.
(WebCore::FilterEffect::setMaxEffectRect): Deleted.
* rendering/CSSFilter.cpp:
(WebCore::CSSFilter::lastEffect const):
(WebCore::CSSFilter::lastEffect): Deleted.
(WebCore::CSSFilter::determineFilterPrimitiveSubregion): Deleted.
* rendering/CSSFilter.h:
* rendering/RenderLayerFilters.cpp:
(WebCore::RenderLayerFilters::beginFilterEffect):
* rendering/svg/RenderSVGResourceFilter.cpp:
(WebCore::RenderSVGResourceFilter::applyResource):
* rendering/svg/SVGRenderingContext.cpp:
(WebCore::SVGRenderingContext::createImageBuffer):
* svg/graphics/filters/SVGFilter.h:

LayoutTests:

Unskip two layout tests which were skipped in r285597.

* TestExpectations:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (286525 => 286526)


--- trunk/LayoutTests/ChangeLog	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/LayoutTests/ChangeLog	2021-12-04 06:12:25 UTC (rev 286526)
@@ -1,3 +1,14 @@
+2021-12-03  Said Abou-Hallawa  <[email protected]>
+
+        [GPU Process] (REGRESSION r285597): Fix SVGFilter clamping calculation
+        https://bugs.webkit.org/show_bug.cgi?id=233843
+
+        Reviewed by Simon Fraser.
+
+        Unskip two layout tests which were skipped in r285597.
+
+        * TestExpectations:
+
 2021-12-03  Lauro Moura  <[email protected]>
 
         [GLIB] Gardening some consistent timeouts

Modified: trunk/LayoutTests/TestExpectations (286525 => 286526)


--- trunk/LayoutTests/TestExpectations	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/LayoutTests/TestExpectations	2021-12-04 06:12:25 UTC (rev 286526)
@@ -5174,10 +5174,8 @@
 webkit.org/b/232705 fast/filter-image/filter-image-blur.html [ Skip ]
 webkit.org/b/232705 fast/filter-image/filter-image-svg.html [ Skip ]
 webkit.org/b/232705 fast/filter-image/filter-image.html [ Skip ]
-webkit.org/b/232705 imported/blink/svg/filters/filter-huge-clamping.svg [ Skip ]
 webkit.org/b/232705 imported/mozilla/svg/dynamic-filter-contents-01a.svg [ Skip ]
 webkit.org/b/232705 imported/mozilla/svg/filters/feComposite-2.svg [ Skip ]
 webkit.org/b/232705 imported/mozilla/svg/filters/feSpecularLighting-1.svg [ Skip ]
 webkit.org/b/232705 svg/custom/resources-css-scaled.html [ Skip ]
 webkit.org/b/232705 svg/filters/feLighting-clipped.svg [ Skip ]
-webkit.org/b/232705 svg/filters/big-sized-off-viewport-filter.svg [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (286525 => 286526)


--- trunk/Source/WebCore/ChangeLog	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/ChangeLog	2021-12-04 06:12:25 UTC (rev 286526)
@@ -1,3 +1,60 @@
+2021-12-03  Said Abou-Hallawa  <[email protected]>
+
+        [GPU Process] (REGRESSION r285597): Fix SVGFilter clamping calculation
+        https://bugs.webkit.org/show_bug.cgi?id=233843
+
+        Reviewed by Simon Fraser.
+
+        In this patch:
+
+        1. lastEffect() is made virtual function of Filter and it's already 
+           implemented as non-virtual function in both CSSFilter and SVGFilter.
+
+        2. The clamping calculations for SVGFilter and CSSFilter are merged in
+           one function called Filter::clampFilterRegionIfNeeded(). This merge
+           makes the new function is the only caller to FilterEffect::maxEffectRect().
+
+        3. Remove FilterEffect::maxEffectRect() . It can be calculated by clipping
+           the FilterEffect::filterPrimitiveSubregion() to filterRegion() and then
+           scaling the result by filterScale().
+
+        4. In RenderSVGResourceFilter::applyResource() we need to pass the non-
+           scaled drawingRegion to ImageBuffer::sizeNeedsClamping() because this
+           function starts by scaling the argument 'size' by the argument 'scale'.
+           So we were doubling the scaling by passing 'absoluteDrawingRegion'
+
+        5. SVGRenderingContext::createImageBuffer() needs to use ImageBuffer::
+           sizeNeedsClamping() instead of using ImageBuffer::clampedSize(). The
+           former function clamps the size to the MaxClampedArea. But the later
+           function shrinks the size to { MaxClampedLength, MaxClampedLength }.
+           When calling createImageBuffer() from RenderSVGResourceFilter::
+           applyResource() we do not expect any further clamping. But if we pass
+           a size with a side  greater than MaxClampedLength to clampedSize(),
+           it  will be clamped even if the area is less than MaxClampedArea. And
+           for filters we clamp to the area.
+
+        * platform/graphics/filters/Filter.cpp:
+        (WebCore::Filter::clampFilterRegionIfNeeded):
+        * platform/graphics/filters/Filter.h:
+        * platform/graphics/filters/FilterEffect.cpp:
+        (WebCore::FilterEffect::determineFilterPrimitiveSubregion):
+        (WebCore::FilterEffect::apply):
+        * platform/graphics/filters/FilterEffect.h:
+        (WebCore::FilterEffect::maxEffectRect const): Deleted.
+        (WebCore::FilterEffect::setMaxEffectRect): Deleted.
+        * rendering/CSSFilter.cpp:
+        (WebCore::CSSFilter::lastEffect const):
+        (WebCore::CSSFilter::lastEffect): Deleted.
+        (WebCore::CSSFilter::determineFilterPrimitiveSubregion): Deleted.
+        * rendering/CSSFilter.h:
+        * rendering/RenderLayerFilters.cpp:
+        (WebCore::RenderLayerFilters::beginFilterEffect):
+        * rendering/svg/RenderSVGResourceFilter.cpp:
+        (WebCore::RenderSVGResourceFilter::applyResource):
+        * rendering/svg/SVGRenderingContext.cpp:
+        (WebCore::SVGRenderingContext::createImageBuffer):
+        * svg/graphics/filters/SVGFilter.h:
+
 2021-12-03  Chris Dumez  <[email protected]>
 
         Add BroadcastChannel, COOP, COEP and Web Locks to features.json

Modified: trunk/Source/WebCore/platform/graphics/filters/Filter.cpp (286525 => 286526)


--- trunk/Source/WebCore/platform/graphics/filters/Filter.cpp	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/platform/graphics/filters/Filter.cpp	2021-12-04 06:12:25 UTC (rev 286526)
@@ -26,7 +26,9 @@
 #include "config.h"
 #include "Filter.h"
 
+#include "FilterEffect.h"
 #include "FilterImage.h"
+#include "ImageBuffer.h"
 
 namespace WebCore {
 
@@ -76,6 +78,26 @@
     return m_clipOperation == ClipOperation::Intersect ? intersection(imageRect, maxEffectRect) : unionRect(imageRect, maxEffectRect);
 }
 
+bool Filter::clampFilterRegionIfNeeded()
+{
+    auto lastEffect = this->lastEffect();
+    lastEffect->determineFilterPrimitiveSubregion(*this);
+    
+    auto maxEffectRect = this->maxEffectRect(lastEffect->filterPrimitiveSubregion());
+    auto scaledMaxEffectRect = scaledByFilterScale(maxEffectRect);
+
+    FloatSize clampingScale(1, 1);
+    if (!ImageBuffer::sizeNeedsClamping(scaledMaxEffectRect.size(), clampingScale))
+        return false;
+
+    m_filterScale = m_filterScale * clampingScale;
+
+    // At least one FilterEffect has a too big image size,
+    // recalculate the effect sizes with new scale factors.
+    lastEffect->determineFilterPrimitiveSubregion(*this);
+    return true;
+}
+
 RefPtr<FilterImage> Filter::apply(ImageBuffer* sourceImage)
 {
     setSourceImage(sourceImage);

Modified: trunk/Source/WebCore/platform/graphics/filters/Filter.h (286525 => 286526)


--- trunk/Source/WebCore/platform/graphics/filters/Filter.h	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/platform/graphics/filters/Filter.h	2021-12-04 06:12:25 UTC (rev 286526)
@@ -67,6 +67,10 @@
     FloatRect maxEffectRect(const FloatRect& primitiveSubregion) const;
     FloatRect clipToMaxEffectRect(const FloatRect& imageRect, const FloatRect& primitiveSubregion) const;
 
+    virtual RefPtr<FilterEffect> lastEffect() const = 0;
+
+    bool clampFilterRegionIfNeeded();
+    
     virtual RefPtr<FilterImage> apply() = 0;
     WEBCORE_EXPORT RefPtr<FilterImage> apply(ImageBuffer* sourceImage);
 

Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp (286525 => 286526)


--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp	2021-12-04 06:12:25 UTC (rev 286526)
@@ -70,13 +70,7 @@
             primitiveSubregion.setHeight(*height);
     }
 
-    // Clip every filter effect to the filter region.
-    auto absoluteMaxEffectRect = filter.maxEffectRect(primitiveSubregion);
-    absoluteMaxEffectRect.scale(filter.filterScale());
-
     setFilterPrimitiveSubregion(primitiveSubregion);
-    setMaxEffectRect(absoluteMaxEffectRect);
-
     return primitiveSubregion;
 }
 
@@ -127,7 +121,7 @@
         << "FilterEffect " << filterName() << " " << this << " apply():"
         << "\n  filterPrimitiveSubregion " << m_filterPrimitiveSubregion
         << "\n  absolutePaintRect " << absoluteImageRect
-        << "\n  maxEffectRect " << m_maxEffectRect
+        << "\n  maxEffectRect " << filter.scaledByFilterScale(filter.maxEffectRect(m_filterPrimitiveSubregion))
         << "\n  filter scale " << filter.filterScale());
 
     return applier->apply(filter, inputFilterImages, *m_filterImage);

Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h (286525 => 286526)


--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h	2021-12-04 06:12:25 UTC (rev 286526)
@@ -56,9 +56,6 @@
     // Recurses on inputs.
     FloatRect determineFilterPrimitiveSubregion(const Filter&);
 
-    FloatRect maxEffectRect() const { return m_maxEffectRect; }
-    void setMaxEffectRect(const FloatRect& maxEffectRect) { m_maxEffectRect = maxEffectRect; }
-
     bool apply(const Filter&) override;
 
     // Correct any invalid pixels, if necessary, in the result of a filter operation.
@@ -96,10 +93,6 @@
 
     RefPtr<FilterImage> m_filterImage;
 
-    // The maximum size of a filter primitive. In SVG this is the primitive subregion in absolute coordinate space.
-    // The absolute paint rect should never be bigger than m_maxEffectRect.
-    FloatRect m_maxEffectRect;
-    
     // The subregion of a filter primitive according to the SVG Filter specification in local coordinates.
     // This is SVG specific and needs to move to RenderSVGResourceFilterPrimitive.
     FloatRect m_filterPrimitiveSubregion;

Modified: trunk/Source/WebCore/rendering/CSSFilter.cpp (286525 => 286526)


--- trunk/Source/WebCore/rendering/CSSFilter.cpp	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/rendering/CSSFilter.cpp	2021-12-04 06:12:25 UTC (rev 286526)
@@ -31,7 +31,6 @@
 #include "FEComponentTransfer.h"
 #include "FEDropShadow.h"
 #include "FEGaussianBlur.h"
-#include "FEMerge.h"
 #include "FilterOperations.h"
 #include "GraphicsContext.h"
 #include "LengthFunctions.h"
@@ -43,10 +42,6 @@
 #include "SVGFilterElement.h"
 #include "SourceGraphic.h"
 
-#if USE(DIRECT2D)
-#include <d2d1.h>
-#endif
-
 namespace WebCore {
 
 RefPtr<CSSFilter> CSSFilter::create(const FilterOperations& operations, RenderingMode renderingMode, float scaleFactor, ClipOperation clipOperation)
@@ -336,7 +331,7 @@
     return true;
 }
 
-RefPtr<FilterEffect> CSSFilter::lastEffect()
+RefPtr<FilterEffect> CSSFilter::lastEffect() const
 {
     if (m_functions.isEmpty())
         return nullptr;
@@ -363,19 +358,6 @@
 }
 #endif
 
-void CSSFilter::determineFilterPrimitiveSubregion()
-{
-    auto effect = lastEffect();
-    effect->determineFilterPrimitiveSubregion(*this);
-    FloatRect subRegion = effect->maxEffectRect();
-    // At least one FilterEffect has a too big image size, recalculate the effect sizes with new scale factors.
-    FloatSize filterScale { 1, 1 };
-    if (ImageBuffer::sizeNeedsClamping(subRegion.size(), filterScale)) {
-        setFilterScale(filterScale);
-        effect->determineFilterPrimitiveSubregion(*this);
-    }
-}
-
 void CSSFilter::clearIntermediateResults()
 {
     for (auto& function : m_functions)

Modified: trunk/Source/WebCore/rendering/CSSFilter.h (286525 => 286526)


--- trunk/Source/WebCore/rendering/CSSFilter.h	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/rendering/CSSFilter.h	2021-12-04 06:12:25 UTC (rev 286526)
@@ -46,16 +46,15 @@
 
     void setSourceImageRect(const FloatRect&);
     bool buildFilterFunctions(RenderElement&, const FilterOperations&);
-    void determineFilterPrimitiveSubregion();
 
     bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; }
     bool hasFilterThatShouldBeRestrictedBySecurityOrigin() const { return m_hasFilterThatShouldBeRestrictedBySecurityOrigin; }
 
-    RefPtr<FilterEffect> lastEffect();
-    IntOutsets outsets() const override;
+    RefPtr<FilterEffect> lastEffect() const final;
+    IntOutsets outsets() const final;
 
     void clearIntermediateResults();
-    RefPtr<FilterImage> apply() override;
+    RefPtr<FilterImage> apply() final;
 
     bool updateBackingStoreRect(const FloatRect& filterRect);
 
@@ -65,7 +64,7 @@
     CSSFilter(RenderingMode, float scaleFactor, ClipOperation, bool hasFilterThatMovesPixels, bool hasFilterThatShouldBeRestrictedBySecurityOrigin);
 
 #if USE(CORE_IMAGE)
-    bool supportsCoreImageRendering() const override;
+    bool supportsCoreImageRendering() const final;
 #endif
 
     bool m_hasFilterThatMovesPixels { false };

Modified: trunk/Source/WebCore/rendering/RenderLayerFilters.cpp (286525 => 286526)


--- trunk/Source/WebCore/rendering/RenderLayerFilters.cpp	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/rendering/RenderLayerFilters.cpp	2021-12-04 06:12:25 UTC (rev 286526)
@@ -180,7 +180,7 @@
     m_paintOffset = filterSourceRect.location();
     resetDirtySourceRect();
 
-    filter.determineFilterPrimitiveSubregion();
+    filter.clampFilterRegionIfNeeded();
 
     if (hasUpdatedBackingStore)
         allocateBackingStore(destinationContext);

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp (286525 => 286526)


--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp	2021-12-04 06:12:25 UTC (rev 286526)
@@ -122,9 +122,7 @@
     filterData->drawingRegion.intersect(filterData->boundaries);
 
     // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize.
-    FloatRect absoluteDrawingRegion = filterData->drawingRegion;
-    absoluteDrawingRegion.scale(filterScale);
-    ImageBuffer::sizeNeedsClamping(absoluteDrawingRegion.size(), filterScale);
+    ImageBuffer::sizeNeedsClamping(filterData->drawingRegion.size(), filterScale);
 
     // Set the rendering mode from the page's settings.
     auto renderingMode = renderer.settings().acceleratedFiltersEnabled() ? RenderingMode::Accelerated : RenderingMode::Unaccelerated;
@@ -137,21 +135,9 @@
         return false;
     }
 
-    auto lastEffect = filterData->builder->lastEffect();
-    ASSERT(lastEffect);
-
-    LOG_WITH_STREAM(Filters, stream << "RenderSVGResourceFilter::applyResource\n" << *filterData->builder->lastEffect());
-
-    lastEffect->determineFilterPrimitiveSubregion(*filterData->filter);
-    FloatRect subRegion = lastEffect->maxEffectRect();
-
-    // At least one FilterEffect has a too big image size,
-    // recalculate the effect sizes with new scale factors.
-    if (ImageBuffer::sizeNeedsClamping(subRegion.size(), filterScale)) {
-        filterData->filter->setFilterScale(filterScale);
-        lastEffect->determineFilterPrimitiveSubregion(*filterData->filter);
-    }
-
+    if (filterData->filter->clampFilterRegionIfNeeded())
+        filterScale = filterData->filter->filterScale();
+    
     // If the drawingRegion is empty, we have something like <g filter=".."/>.
     // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
     if (filterData->drawingRegion.isEmpty()) {

Modified: trunk/Source/WebCore/rendering/svg/SVGRenderingContext.cpp (286525 => 286526)


--- trunk/Source/WebCore/rendering/svg/SVGRenderingContext.cpp	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/rendering/svg/SVGRenderingContext.cpp	2021-12-04 06:12:25 UTC (rev 286526)
@@ -235,8 +235,10 @@
     if (paintRect.isEmpty())
         return nullptr;
 
-    FloatSize scale;
-    FloatSize clampedSize = ImageBuffer::clampedSize(paintRect.size(), scale);
+    FloatSize scale(1, 1);
+    FloatSize clampedSize = paintRect.size();
+    if (ImageBuffer::sizeNeedsClamping(clampedSize, scale))
+        clampedSize = clampedSize * scale;
 
 #if USE(DIRECT2D)
     auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, context, 1, colorSpace, PixelFormat::BGRA8);

Modified: trunk/Source/WebCore/svg/graphics/filters/SVGFilter.h (286525 => 286526)


--- trunk/Source/WebCore/svg/graphics/filters/SVGFilter.h	2021-12-04 03:30:03 UTC (rev 286525)
+++ trunk/Source/WebCore/svg/graphics/filters/SVGFilter.h	2021-12-04 06:12:25 UTC (rev 286526)
@@ -42,9 +42,9 @@
 
     FloatRect targetBoundingBox() const { return m_targetBoundingBox; }
 
-    RefPtr<FilterEffect> lastEffect() const { return !m_expression.isEmpty() ? m_expression.last() : nullptr; }
+    RefPtr<FilterEffect> lastEffect() const final { return !m_expression.isEmpty() ? m_expression.last() : nullptr; }
 
-    RefPtr<FilterImage> apply() override;
+    RefPtr<FilterImage> apply() final;
 
 private:
     SVGFilter(RenderingMode, const FloatSize& filterScale, const FloatRect& sourceImageRect, const FloatRect& filterRegion, ClipOperation, const FloatRect& targetBoundingBox, SVGUnitTypes::SVGUnitType primitiveUnits);
@@ -54,14 +54,14 @@
     void setEffectGeometryMap(FilterEffectGeometryMap&& effectGeometryMap) { m_effectGeometryMap = WTFMove(effectGeometryMap); }
 
 #if USE(CORE_IMAGE)
-    bool supportsCoreImageRendering() const override;
+    bool supportsCoreImageRendering() const final;
 #endif
-    std::optional<FilterEffectGeometry> effectGeometry(FilterEffect&) const override;
+    std::optional<FilterEffectGeometry> effectGeometry(FilterEffect&) const final;
     FloatSize resolvedSize(const FloatSize&) const final;
 
-    bool apply(const Filter&) override;
-    IntOutsets outsets() const override;
-    void clearResult() override;
+    bool apply(const Filter&) final;
+    IntOutsets outsets() const final;
+    void clearResult() final;
 
     FloatRect m_targetBoundingBox;
     SVGUnitTypes::SVGUnitType m_primitiveUnits;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to