NEW 282530
mask-image broken with mask-mode: luminance
https://bugs.webkit.org/show_bug.cgi?id=282530
Summary mask-image broken with mask-mode: luminance
Tuur Martens
Reported 2024-11-04 02:42:16 PST
Created attachment 473123 [details] minimal reproduction file Sorry for the bad title. I've been trying to find out exactly what is going on, but it hasn't been easy. Anyhow, I'm not sure of exactly what triggers this bug, which I realize isn't very helpful. I'll post this here so perhaps more eyes could look into it, as will I, as much as is possible. Scenario sketch: I want a gradient "blob". I tried to use a blurred out SVG for that, but that caused rendering issues in every single browser I tried. So we opted to use a solid color div with a mask applied to it. I got the mask small enough to fit in 1.5KiB, so it's part of the html file because I can only seem to attach one attachment. For some reason this mask works only sometimes, and the only browsers where I encounter issues are webkit-based. In the attached file it seems to work on some window widths, but not others, so try messing with the window size. Once again my apologies for making such a vague report, but my intention is to bring more eyes upon the issue. What actually happens: The result SOMETIMES is a solid color, as if the mask was never applied. Other times, it behaves as expected. Possibly related to image size. What is supposed to happen: The mask is visually applied. Reproduced in: WebKitGTK 2.46.1 GStreamer 1.24.7 GTK 4.17.0 Libadwaita 1.7.0 Distributor: GNOME
Attachments
minimal reproduction file (2.50 KB, text/html)
2024-11-04 02:42 PST, Tuur Martens
no flags
Clearer testcase (4.70 KB, text/html)
2024-11-05 09:55 PST, Simon Fraser (smfr)
no flags
Svg minimal Reproduction (1.05 KB, text/html)
2024-11-27 02:53 PST, derplayer2001
no flags
rendering in safari, firefox, chrome (2.34 MB, image/png)
2025-05-19 18:54 PDT, Karl Dubost
no flags
Alexey Proskuryakov
Comment 1 2024-11-04 13:14:21 PST
I can reproduce this in Safari too.
Simon Fraser (smfr)
Comment 2 2024-11-05 09:55:40 PST
Created attachment 473145 [details] Clearer testcase Seems to happen when things go above a certain size.
Radar WebKit Bug Importer
Comment 3 2024-11-05 09:56:57 PST
Simon Fraser (smfr)
Comment 4 2024-11-05 09:58:01 PST
It's not about the WebP image; this happens with a gradient too.
Simon Fraser (smfr)
Comment 5 2024-11-05 10:04:04 PST
Drawing commands for the good state: handleItem save handleItem clip (rect (8,50) width=1272 height=833) handleItem begin-transparency-layer (opacity 1.00) handleItem fill-composited-rect (rect (8,50) width=1272 height=833) (color #FF0000) (composite-operation source-over) (blend-mode normal) handleItem set-state (change-flags [composite-mode]) (composite-mode (composite-operation destination-in) (blend-mode normal)) handleItem begin-transparency-layer (opacity 1.00) handleItem set-state (change-flags [draw-luminance-mask]) (draw-luminance-mask 1) handleItem save handleItem clip (rect (8,50) width=1272 height=833) handleItem save handleItem set-state (change-flags [composite-mode]) (composite-mode (composite-operation source-over) (blend-mode normal)) handleItem clip (rect (8,50) width=1272 height=833) handleItem translate (x 8.00) (y 50.00) handleItem fill-rect-with-gradient (rect (0,0) width=1272 height=833) handleItem restore handleItem restore handleItem end-transparency-layer handleItem end-transparency-layer handleItem restore Drawing commands for the bad state: handleItem save handleItem clip (rect (8,50) width=1199 height=833) handleItem begin-transparency-layer (opacity 1.00) handleItem fill-composited-rect (rect (8,50) width=1199 height=833) (color #FF0000) (composite-operation source-over) (blend-mode normal) handleItem set-state (change-flags [composite-mode]) (composite-mode (composite-operation destination-in) (blend-mode normal)) handleItem begin-transparency-layer (opacity 1.00) handleItem set-state (change-flags [draw-luminance-mask]) (draw-luminance-mask 0) handleItem draw-pattern (image-identifier 479) (pattern-transform {m=((0.50,0.00)(0.00,0.50)) t=(0.00,0.00)}) (tile-rect (0,0) width=2 height=1666) (dest-rect (8,50) width=1199 height=833) (phase (8,50)) (spacing width=0 height=0) handleItem end-transparency-layer handleItem end-transparency-layer handleItem restore
Simon Fraser (smfr)
Comment 6 2024-11-05 17:16:05 PST
Here's the reason for the divergence: const float maxPatternTilePixels = 2048 * 2048;
Simon Fraser (smfr)
Comment 7 2024-11-05 17:51:46 PST Comment hidden (obsolete)
Simon Fraser (smfr)
Comment 8 2024-11-05 18:09:07 PST
`mask-mode: luminance` just seems broken in general.
derplayer2001
Comment 9 2024-11-25 10:55:35 PST
I'm having the same bug with a very lightweight svg that im masking, curiously the result changes from Safari on IOS to Safari on OSX as I only encounter it on IOS... smaller size seems to fix the problem though.
derplayer2001
Comment 10 2024-11-27 02:53:46 PST
Created attachment 473379 [details] Svg minimal Reproduction
Estelle Weyl
Comment 11 2025-05-19 18:10:06 PDT
mask-mode is broken in safari because mask-type for `<mask>` defaults to `alpha` when it should default to luminance, therefore `mask-mode: match-source` is usually incorrect. See https://github.com/mdn/browser-compat-data/issues/26632
Karl Dubost
Comment 12 2025-05-19 18:53:34 PDT
Strange. https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/rendering/style/RenderStyleConstants.h#376-382 ```cpp // CSS3 Mask Mode enum class MaskMode : uint8_t { Alpha, Luminance, MatchSource, }; ``` https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/rendering/style/SVGRenderStyleDefs.h#140-143 ```cpp enum class MaskType : uint8_t { Luminance, Alpha }; ``` and https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/rendering/style/SVGRenderStyle.h#95 ```cpp static MaskType initialMaskType() { return MaskType::Luminance; } ``` https://drafts.fxtf.org/css-masking/#the-mask-mode <masking-mode> = alpha | luminance | match-source Initial: match-source https://drafts.fxtf.org/css-masking/#propdef-mask-type Value: luminance | alpha Initial: luminance
Karl Dubost
Comment 13 2025-05-19 18:54:30 PDT
Created attachment 475312 [details] rendering in safari, firefox, chrome Safari Technology Preview 18.4 20622.1.12 Firefox Nightly 140.0a1 14025.5.8 Google Chrome Canary 138.0.7189.0 7189.0
Karl Dubost
Comment 14 2025-05-19 19:00:05 PDT
https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp#137-138 ```cpp if (svgStyle->maskType() == MaskType::Luminance) maskImage->convertToLuminanceMask(); ``` https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/platform/graphics/ImageBuffer.cpp#501-505 ```cpp void ImageBuffer::convertToLuminanceMask() { if (auto* backend = ensureBackend()) backend->convertToLuminanceMask(); } ``` https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/platform/graphics/ImageBufferBackend.cpp#74-97 ```cpp void ImageBufferBackend::convertToLuminanceMask() { IntRect sourceRect { { }, size() }; PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, colorSpace() }; auto pixelBuffer = ImageBufferAllocator().createPixelBuffer(format, sourceRect.size()); if (!pixelBuffer) return; getPixelBuffer(sourceRect, *pixelBuffer); unsigned pixelArrayLength = pixelBuffer->bytes().size(); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { uint8_t a = pixelBuffer->item(pixelOffset + 3); if (!a) continue; uint8_t r = pixelBuffer->item(pixelOffset); uint8_t g = pixelBuffer->item(pixelOffset + 1); uint8_t b = pixelBuffer->item(pixelOffset + 2); double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0); pixelBuffer->set(pixelOffset + 3, luma); } putPixelBuffer(*pixelBuffer, sourceRect, IntPoint::zero(), AlphaPremultiplication::Premultiplied); } ```
Karl Dubost
Comment 15 2025-05-19 19:02:39 PDT
(In reply to derplayer2001 from comment #9) > I'm having the same bug with a very lightweight svg that im masking, > curiously the result changes from Safari on IOS to Safari on OSX as I only > encounter it on IOS... smaller size seems to fix the problem though. this would align with what Simon was mentioning. https://searchfox.org/wubkat/rev/46bcbfb3cf5ebc591f1c02f41c178e1d13062554/Source/WebCore/platform/graphics/Image.cpp#253-261 ```cpp // Patterned images and gradients can use lots of memory for caching when the // tile size is large (<rdar://problem/4691859>, <rdar://problem/6239505>). // Memory consumption depends on the transformed tile size which can get // larger than the original tile if user zooms in enough. #if PLATFORM(IOS_FAMILY) const float maxPatternTilePixels = 512 * 512; #else const float maxPatternTilePixels = 2048 * 2048; #endif ```
Note You need to log in before you can comment on or make changes to this bug.