Bug 1624532. Handle incomplete masks on svg content properly with webrender. r=mstange,jrmuizel

The basic problem here for the page is that we should draw an svg element as if it has no mask specified if the specified mask is display: none. (For html elements in the same situation we should not draw the html element at all.)

The fix is to treat the return values of PaintMaskSurface (which come through nsSVGIntegrationUtils::PaintMask and nsDisplayMasksAndClipPaths::PaintMask) in WebRenderCommandBuilder::BuildWrMaskImage the same way as in CreateAndPaintMaskSurface.

Differential Revision: https://phabricator.services.mozilla.com/D70596

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Timothy Nikkel 2020-04-14 17:08:52 +00:00
parent c059e75bef
commit 59bd6d0dee
3 changed files with 137 additions and 0 deletions

View File

@ -2499,6 +2499,24 @@ Maybe<wr::ImageMask> WebRenderCommandBuilder::BuildWrMaskImage(
return Nothing();
}
// If a mask is incomplete or missing (e.g. it's display: none) the proper
// behaviour depends on the masked frame being html or svg.
//
// For an HTML frame:
// According to css-masking spec, always create a mask surface when
// we have any item in maskFrame even if all of those items are
// non-resolvable <mask-sources> or <images> so continue with the
// painting code. Note that in a common case of no layer of the mask being
// complete or even partially complete then the mask surface will be
// transparent black so this results in hiding the frame.
// For an SVG frame:
// SVG 1.1 say that if we fail to resolve a mask, we should draw the
// object unmasked so return Nothing().
if (!maskIsComplete &&
(aMaskItem->Frame()->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
return Nothing();
}
recorder->FlushItem(IntRect(0, 0, size.width, size.height));
recorder->Finish();

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px; background: red"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px; background: red"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px;"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px;"></div>
</foreignObject>
</svg>
<!-- make sure masking actually works -->
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="50" fill="red"></rect>
<rect x="0" y="100" width="100" height="50" fill="red"></rect>
</svg>
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="50" fill="red"></rect>
<rect x="0" y="100" width="100" height="50" fill="red"></rect>
</svg>
<!-- make sure masking works on active content -->
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="50" fill="red"></rect>
<rect x="0" y="100" width="100" height="50" fill="red"></rect>
</svg>
<svg width="200" height="200">
<rect x="0" y="0" width="100" height="50" fill="red"></rect>
<rect x="0" y="100" width="100" height="50" fill="red"></rect>
</svg>
</body>
</html>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="match" href="display-none-mask-ref.html" />
</head>
<body>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200" style="mask: url('#notfound');">
<div style="width: 200px; height: 200px; background: red"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200" style="mask: url('#noneMask');">
<div style="width: 200px; height: 200px; background: red"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px; background: red; mask: url('#notfound');"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px; background: red; mask: url('#noneMask');"></div>
</foreignObject>
</svg>
<svg width="200" height="200" style="display:none">
<defs>
<mask id="noneMask">
<rect x="0" y="0" width="200" height="200" fill="#4d4d4d"></rect>
</mask>
</defs>
</svg>
<!-- make sure masking actually works -->
<svg width="200" height="200">
<defs>
<mask id="aMask">
<rect x="0" y="0" width="100" height="50" fill="#ffffff"></rect>
<rect x="0" y="100" width="100" height="50" fill="#ffffff"></rect>
</mask>
</defs>
<foreignObject x="0" y="0" width="200" height="200" style="mask: url('#aMask');">
<div style="width: 200px; height: 200px; background: red;"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px; background: red; mask: url('#aMask');"></div>
</foreignObject>
</svg>
<!-- make sure masking works on active content -->
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200" style="mask: url('#aMask');">
<div style="width: 200px; height: 200px; background: red; will-change: transform"></div>
</foreignObject>
</svg>
<svg width="200" height="200">
<foreignObject x="0" y="0" width="200" height="200">
<div style="width: 200px; height: 200px; background: red; will-change: transform; mask: url('#aMask');"></div>
</foreignObject>
</svg>
</body>
</html>