Bug 172338 - SVG mask is not applied as a group effect
Summary: SVG mask is not applied as a group effect
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: SVG (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar, LayerBasedSVGEngine
Depends on:
Blocks:
 
Reported: 2017-05-18 21:57 PDT by Simon Fraser (smfr)
Modified: 2024-03-13 15:05 PDT (History)
9 users (show)

See Also:


Attachments
Reduced test case (685 bytes, text/html)
2017-05-24 21:34 PDT, Simon Fraser (smfr)
no flags Details
Safari 15.6 differs from other browsers (948.19 KB, image/png)
2022-08-03 14:20 PDT, Ahmad Saleem
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Simon Fraser (smfr) 2017-05-18 21:57:09 PDT
https://codepen.io/AmeliaBR/details/OmBjxX/

The left two sets of circles should look the same
Comment 1 Simon Fraser (smfr) 2017-05-24 21:34:43 PDT
Created attachment 311193 [details]
Reduced test case
Comment 2 Simon Fraser (smfr) 2017-05-24 21:36:27 PDT
RenderSVGResourceMasker::applyResource) is painting the mask into a buffer, and then calling SVGRenderingContext::clipToImageBuffer() with that.

Interestingly, GraphicsContext::clipToImageBuffer() has a comment:

    // FIXME: This image needs to be grayscale to be used as an alpha mask here.
Comment 3 Simon Fraser (smfr) 2017-05-24 21:56:57 PDT
Actually I think it's just wrong that RenderSVGResourceMasker::applyResource() thinks it can call clipToImageBuffer() before the masked drawing commands; this doesn't result in a graphical group. I think masking needs to be more like a filter, which paints into an offscreen buffer then masks.
Comment 4 Jan Bösenberg 2018-05-17 00:59:53 PDT
Simon is correct, the painting has to be done into an offscreen buffer, on which the mask is then applied.

The relevant part in the SVG spec is here:

  https://www.w3.org/TR/SVG11/render.html#ClippingMaskingObjectOpacity

Specifically: "In all cases the SVG implementation must behave as though all painting and filtering is first performed to an intermediate canvas which has been initialized to transparent black. Then, alpha values on the intermediate canvas are multiplied by the implicit alpha values from the clipping path, the alpha values from the mask, and the alpha values from the ‘opacity’ property."
Comment 5 Jan Bösenberg 2018-05-17 01:25:36 PDT
Here is an example that should make it obvious that masking is not being done correctly.

The same structure of two overlapping squares is displayed twice. The only difference on the right side is that an empty filter is added to the group containing the squares. Obviously this should not make a difference, but with Webkit the squares have different colors.

The reason behind this is that in the first case the mask is applied to the squares before they are rendered. The red and blue squares get opacity of 0.5, and consequently the resulting square appears purple.

In the second case the empty filter is applied to the group first. The intermediate result is a blue square, which is then masked.

Here is the SVG (here as a JSBin: http://jsbin.com/fovatajayu/edit?html,output)

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="512" viewBox="0,0,512,512" color-interpolation="sRGB" >
  <defs>
    <mask id="mask1" maskContentUnits="objectBoundingBox"> 
      <rect  x="0" y="0" width="100" height="100" fill="#808080"/>
    </mask>

    <filter id="filter1"> <!-- This filter does nothing -->
      <feColorMatrix values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0" />
    </filter>
  </defs>

  <g mask="url(#mask1)"  >
    <g>
      <rect x="0" y="0" width="256" height="256" fill="red"  />
      <rect x="0" y="0" width="256" height="256" fill="blue" />
    </g>
  </g>

  <!-- Empty filter added -->
  <g mask="url(#mask1)">
    <g filter="url(#filter1)">
      <rect x="300" y="0" width="256" height="256" fill="red"  />
      <rect x="300" y="0" width="256" height="256" fill="blue" />
    </g>
  </g>
</svg>
Comment 6 Radar WebKit Bug Importer 2018-05-30 08:33:28 PDT
<rdar://problem/40650896>
Comment 7 Jan Bösenberg 2018-08-19 23:59:18 PDT
Another argument for fixing this bug (besides this being a bug) is that a fix would probably improve performance considerable for more complex SVGs that make use masks.

Currently WebKit applies the mask on each shape or path in the element's subtree, while the correct implementation first flattens the subtree and then applies the mask on the resulting graphics, which obvioulsy is much faster if many shapes or paths exist in the subtree.
Comment 8 Ahmad Saleem 2022-08-03 14:20:58 PDT
Created attachment 461387 [details]
Safari 15.6 differs from other browsers

I am able to reproduce this bug in Safari 15.6 on macOS 12.5 using attached test case as can be seen from the attached screenshot. Further, I am able to reproduce similarly using from Comment 05.

I think it is similar to this bug, which got fixed in Chrome (but I could be wrong and it might be different issue - although Chrome Test case also broken in Safari):

https://chromium.googlesource.com/chromium/src/+/7766f1ca1a9166d97f3f751d2f210f8db05ecbfd

Chrome bug - Test Case - https://svgshare.com/i/RuQ.svg
Comment 9 Ahmad Saleem 2023-05-20 10:32:25 PDT
(In reply to Ahmad Saleem from comment #8)
> Created attachment 461387 [details]
> Safari 15.6 differs from other browsers
> 
> I am able to reproduce this bug in Safari 15.6 on macOS 12.5 using attached
> test case as can be seen from the attached screenshot. Further, I am able to
> reproduce similarly using from Comment 05.
> 
> I think it is similar to this bug, which got fixed in Chrome (but I could be
> wrong and it might be different issue - although Chrome Test case also
> broken in Safari):
> 
> https://chromium.googlesource.com/chromium/src/+/
> 7766f1ca1a9166d97f3f751d2f210f8db05ecbfd
> 
> Chrome bug - Test Case - https://svgshare.com/i/RuQ.svg

https://searchfox.org/wubkat/source/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp#180

https://searchfox.org/wubkat/source/Source/WebCore/rendering/BackgroundPainter.cpp#323

^ Some references - which Chrome patch touches.
Comment 10 Ahmad Saleem 2024-01-22 18:41:46 PST
Works in LBSE - once it is turned on, please close this bug.(In reply to Ahmad Saleem from comment #8)
> Created attachment 461387 [details]
> Safari 15.6 differs from other browsers
> 
> I am able to reproduce this bug in Safari 15.6 on macOS 12.5 using attached
> test case as can be seen from the attached screenshot. Further, I am able to
> reproduce similarly using from Comment 05.
> 
> I think it is similar to this bug, which got fixed in Chrome (but I could be
> wrong and it might be different issue - although Chrome Test case also
> broken in Safari):
> 
> https://chromium.googlesource.com/chromium/src/+/
> 7766f1ca1a9166d97f3f751d2f210f8db05ecbfd
> 
> Chrome bug - Test Case - https://svgshare.com/i/RuQ.svg

Broken in LBSE with - https://svgshare.com/i/RuQ.svg <- this test case.
Comment 11 Ahmad Saleem 2024-03-13 15:01:38 PDT
@Rob - I think we cannot mark this as 'LegacySVG' only since following test case is broken as well:

>> Broken in LBSE with - https://svgshare.com/i/RuQ.svg <- this test case.


^ Mentioned in Comment 10.
Comment 12 Rob Buis 2024-03-13 15:05:56 PDT
(In reply to Ahmad Saleem from comment #11)
> @Rob - I think we cannot mark this as 'LegacySVG' only since following test
> case is broken as well:
> 
> >> Broken in LBSE with - https://svgshare.com/i/RuQ.svg <- this test case.
> 
> 
> ^ Mentioned in Comment 10.

Right, I only checked the attached test case, not the one from the later comments, thanks for checking!