Issue #2355 - Apply self-transforms to the frame of top level <svg>

We previously didn't do this because we relied on our anonymous wrapper
to perform transforms. However, that resulted in only the children
transforming, and the frame's cliprect wouldn't be updated,
giving the impression of the z-ordering being wrong.

Also adds reftests from the relevant BZ bug found later.

Resolves #2355
This commit is contained in:
Moonchild 2023-10-22 09:33:22 +02:00 • committed by roytam1
commit 0bcaa2ff90
9 changed files with 100 additions and 15 deletions

View file

@ -1,22 +1,27 @@
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait"> <html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head> <head>
<title>Testcases for SVG fragment identifiers</title> <title>Testcases for SVG fragment identifiers</title>
<style>
iframe {
border: none;
}
</style>
</head> </head>
<body style="background-color: lime;"> <body style="background-color: lime;">
<div> <div>
<object type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#limeView" /> <iframe scrolling="no" type="image/svg+xml" width="100" height="100" src="fragmentIdentifier-rect-01.svg#limeView" />
<object type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100))" /> <iframe scrolling="no" type="image/svg+xml" width="100" height="100" src="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100))" />
<object type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#view" /> <iframe scrolling="no" type="image/svg+xml" width="100" height="100" src="fragmentIdentifier-rect-01.svg#view" />
</div> </div>
<div> <div>
<object type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,0,100,100);transform(translate(0,200)))" /> <iframe scrolling="no" type="image/svg+xml" width="100" height="100" src="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,0,100,100);transform(translate(0,200)))" />
<object id="replace" type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,0,100,100);transform(translate(0,0))" /> <iframe scrolling="no" id="replace" type="image/svg+xml" width="100" height="100" src="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,0,100,100);transform(translate(0,0))" />
<object id="remove" type="image/svg+xml" width="100" height="100" data="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100);transform(translate(0,200)))" /> <iframe scrolling="no" id="remove" type="image/svg+xml" width="100" height="100" src="fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100);transform(translate(0,200)))" />
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
window.onload = function() { window.onload = function() {
document.getElementById("replace").setAttribute("data","fragmentIdentifier-rect-01.svg#svgView(viewBox(0,0,100,100);transform(translate(0,200)))"); document.getElementById("replace").setAttribute("src","fragmentIdentifier-rect-01.svg#svgView(viewBox(0,0,100,100);transform(translate(0,200)))");
document.getElementById("remove").setAttribute("data","fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100))"); document.getElementById("remove").setAttribute("src","fragmentIdentifier-rect-01.svg#svgView(viewBox(0,200,100,100))");
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
</script> </script>

View file

@ -372,6 +372,7 @@ fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg
== text-white-space-01.svg text-white-space-01-ref.svg == text-white-space-01.svg text-white-space-01-ref.svg
== thin-stroke-01.svg pass.svg == thin-stroke-01.svg pass.svg
== zero-stroke-01.svg pass.svg == zero-stroke-01.svg pass.svg
== transform-outer-svg-01.svg transform-outer-svg-01-ref.svg
== css-transform-svg.html css-transform-svg-ref.html == css-transform-svg.html css-transform-svg-ref.html
== tspan-dxdy-01.svg tspan-dxdy-ref.svg == tspan-dxdy-01.svg tspan-dxdy-ref.svg
== tspan-dxdy-02.svg tspan-dxdy-ref.svg == tspan-dxdy-02.svg tspan-dxdy-ref.svg

View file

@ -42,3 +42,5 @@ fuzzy(1,5000) == mask-clipPath-opacity-01b.xhtml mask-clipPath-opacity-01-ref.xh
fuzzy(1,5000) == mask-clipPath-opacity-01c.xhtml mask-clipPath-opacity-01-ref.xhtml fuzzy(1,5000) == mask-clipPath-opacity-01c.xhtml mask-clipPath-opacity-01-ref.xhtml
fuzzy(1,5000) == mask-clipPath-opacity-01d.xhtml mask-clipPath-opacity-01-ref.xhtml fuzzy(1,5000) == mask-clipPath-opacity-01d.xhtml mask-clipPath-opacity-01-ref.xhtml
fuzzy(1,5000) == mask-clipPath-opacity-01e.xhtml mask-clipPath-opacity-01-ref.xhtml fuzzy(1,5000) == mask-clipPath-opacity-01e.xhtml mask-clipPath-opacity-01-ref.xhtml
== transform-outer-svg-01.xhtml transform-outer-svg-01-ref.xhtml

View file

@ -0,0 +1,18 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test that the 'transform' attribute transforms our border too</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1353697 -->
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250">
<rect x="75" y="75" width="150" height="150" fill="none" stroke="black" stroke-width="50"/>
<rect x="125" y="125" width="50" height="50" fill="blue"/>
</svg>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test that the 'transform' attribute transforms our border too</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1353697 -->
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"
style="border: 50px solid black;" transform="translate(50,50)">
<rect x="25" y="25" width="50" height="50" fill="blue"/>
</svg>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1353697 -->
<rect x="75" y="75" width="150" height="150" fill="none" stroke="black" stroke-width="50"/>
<rect x="125" y="125" width="50" height="50" fill="blue"/>
</svg>

After

Width:  |  Height:  |  Size: 415 B

View file

@ -0,0 +1,10 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"
style="border: 50px solid black;" transform="translate(50,50)">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1353697 -->
<title>Test that the 'transform' attribute transforms our border too</title>
<rect x="25" y="25" width="50" height="50" fill="blue"/>
</svg>

After

Width:  |  Height:  |  Size: 466 B

View file

@ -721,6 +721,32 @@ nsSVGOuterSVGFrame::AttributeChanged(int32_t aNameSpaceID,
return NS_OK; return NS_OK;
} }
bool
nsSVGOuterSVGFrame::IsSVGTransformed(Matrix* aOwnTransform,
Matrix* aFromParentTransform) const
{
// The HasChildrenOnlyTransform() implementation of our anonymous child makes sure
// our transforms are applied to our children as-appropriate. So, we only care
// about self-transforms on our own frame, here.
bool hasTransform = false;
SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent);
nsSVGAnimatedTransformList* animatedTransformList = content->GetAnimatedTransformList();
if ((animatedTransformList && animatedTransformList->HasTransform()) ||
content->GetAnimateMotionTransform()) {
if (aOwnTransform) {
// Apply transform
*aOwnTransform = gfx::ToMatrix(
content->PrependLocalTransformsTo(
gfxMatrix(), eUserSpaceToParent));
}
hasTransform = true;
}
return hasTransform;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// painting // painting

View file

@ -101,13 +101,9 @@ public:
return PrincipalChildList().FirstChild()->GetContentInsertionFrame(); return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
} }
virtual bool IsSVGTransformed(Matrix *aOwnTransform, // Applies only to our own frame, see implementation note.
Matrix *aFromParentTransform) const override { bool IsSVGTransformed(Matrix* aOwnTransform,
// Our anonymous wrapper performs the transforms. We simply Matrix* aFromParentTransform) const override;
// return whether we are transformed here but don't apply the transforms
// themselves.
return PrincipalChildList().FirstChild()->IsSVGTransformed();
}
// nsISVGSVGFrame interface: // nsISVGSVGFrame interface:
virtual void NotifyViewportOrTransformChanged(uint32_t aFlags) override; virtual void NotifyViewportOrTransformChanged(uint32_t aFlags) override;