Bug 1902675 - animations should not run in inactive switch children or if they are children of elements that have failed conditional processing tests r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D213848
This commit is contained in:
longsonr 2024-06-17 16:40:41 +00:00
parent 266c474a97
commit 0d068a2c72
7 changed files with 104 additions and 11 deletions

View File

@ -6,6 +6,7 @@
#include "mozilla/dom/SVGAnimationElement.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "mozilla/dom/SVGSwitchElement.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/SMILAnimationController.h"
@ -152,6 +153,7 @@ nsresult SVGAnimationElement::BindToTree(BindContext& aContext,
mTimedElement.BindToTree(*this);
}
mTimedElement.SetIsDisabled(IsDisabled());
AnimationNeedsResample();
return NS_OK;
@ -228,8 +230,7 @@ void SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
aSubjectPrincipal, aNotify);
if (SVGTests::IsConditionalProcessingAttribute(aName)) {
bool isDisabled = !SVGTests::PassesConditionalProcessingTests();
if (mTimedElement.SetIsDisabled(isDisabled)) {
if (mTimedElement.SetIsDisabled(IsDisabled())) {
AnimationNeedsResample();
}
}
@ -272,6 +273,38 @@ void SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
// next BindToTree call.
}
bool SVGAnimationElement::IsDisabled() {
if (!SVGTests::PassesConditionalProcessingTests()) {
return true;
}
nsIContent* child = this;
while (nsIContent* parent = child->GetFlattenedTreeParent()) {
if (!parent->IsSVGElement()) {
return false;
}
if (auto* svgSwitch = SVGSwitchElement::FromNodeOrNull(parent)) {
nsIFrame* frame = svgSwitch->GetPrimaryFrame();
// If we've been reflowed then the active child has been determined,
// otherwise we'll have to calculate whether this is the active child.
if (frame && !frame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
if (child != svgSwitch->GetActiveChild()) {
return true;
}
} else {
if (child != SVGTests::FindActiveSwitchChild(svgSwitch)) {
return true;
}
}
} else if (auto* svgGraphics = SVGGraphicsElement::FromNode(parent)) {
if (!svgGraphics->PassesConditionalProcessingTests()) {
return true;
}
}
child = parent;
}
return false;
}
//----------------------------------------------------------------------
// SVG utility methods

View File

@ -64,6 +64,8 @@ class SVGAnimationElement : public SVGAnimationElementBase, public SVGTests {
// Utility methods for within SVG
void ActivateByHyperlink();
bool IsDisabled();
// WebIDL
SVGElement* GetTargetElement();
float GetStartTime(ErrorResult& rv);

View File

@ -61,7 +61,7 @@ bool SVGTests::IsConditionalProcessingAttribute(
// Find the best match from aAvailLangs for the users accept-languages,
// returning the index in the aAvailLangs list, or -1 if no match.
int32_t FindBestLanguage(const nsTArray<nsCString>& aAvailLangs) {
static int32_t FindBestLanguage(const nsTArray<nsCString>& aAvailLangs) {
AutoTArray<nsCString, 16> reqLangs;
nsCString acceptLangs;
Preferences::GetLocalizedCString("intl.accept_languages", acceptLangs);

View File

@ -257,16 +257,15 @@ static bool NodeCouldBeRendered(const nsINode& aNode) {
if (const auto* symbol = SVGSymbolElement::FromNode(aNode)) {
return symbol->CouldBeRendered();
}
if (const auto* svgGraphics = SVGGraphicsElement::FromNode(aNode)) {
if (!svgGraphics->PassesConditionalProcessingTests()) {
return false;
}
}
if (auto* svgSwitch =
SVGSwitchElement::FromNodeOrNull(aNode.GetParentNode())) {
if (&aNode != svgSwitch->GetActiveChild()) {
return false;
}
} else if (const auto* svgGraphics = SVGGraphicsElement::FromNode(aNode)) {
if (!svgGraphics->PassesConditionalProcessingTests()) {
return false;
}
}
return true;
}
@ -296,9 +295,8 @@ auto SVGUseElement::ScanAncestors(const Element& aTarget) const -> ScanResult {
return ScanAncestorsInternal(aTarget, count);
}
auto SVGUseElement::ScanAncestorsInternal(const Element& aTarget,
uint32_t& aCount) const
-> ScanResult {
auto SVGUseElement::ScanAncestorsInternal(
const Element& aTarget, uint32_t& aCount) const -> ScanResult {
if (&aTarget == this) {
return ScanResult::CyclicReference;
}

View File

@ -0,0 +1,18 @@
<!doctype html>
<html class="reftest-wait">
<title>Test animation as children of failed conditional processing test elements</title>
<link rel="match" href="../struct/reftests/reference/green-100x100.html">
<script src="/common/reftest-wait.js"></script>
<script src="/common/rendering-utils.js"></script>
<script>
function test() {
document.getElementsByTagName('svg')[0].setCurrentTime(2);
waitForAtLeastOneFrame().then(takeScreenshot);
}
</script>
<svg onload="test()">
<g systemLanguage="x-xl">
<set xlink:href="#test" attributeName="width" begin="2s" to="0" />
</g>
<rect id="test" width="100" height="100" fill="green"/>
</svg>

View File

@ -0,0 +1,19 @@
<!doctype html>
<html class="reftest-wait">
<title>Test animation as children of switch elements</title>
<link rel="match" href="../struct/reftests/reference/green-100x100.html">
<script src="/common/reftest-wait.js"></script>
<script src="/common/rendering-utils.js"></script>
<script>
function test() {
document.getElementsByTagName('svg')[0].setCurrentTime(2);
waitForAtLeastOneFrame().then(takeScreenshot);
}
</script>
<svg onload="test()">
<switch>
<set systemLanguage="x-xl" xlink:href="#test" attributeName="width" begin="2s" to="0" />
<set xlink:href="#test" attributeName="height" begin="2s" to="100" />
</switch>
<rect id="test" width="100" height="0" fill="green"/>
</svg>

View File

@ -0,0 +1,23 @@
<!doctype html>
<html class="reftest-wait">
<title>Test animation as children of switch elements</title>
<link rel="match" href="../struct/reftests/reference/green-100x100.html">
<script src="/common/reftest-wait.js"></script>
<script src="/common/rendering-utils.js"></script>
<script>
function test() {
document.getElementsByTagName('svg')[0].setCurrentTime(2);
waitForAtLeastOneFrame().then(takeScreenshot);
}
</script>
<svg onload="test()">
<switch>
<g systemLanguage="x-xl">
<set xlink:href="#test" attributeName="width" begin="2s" to="0" />
</g>
<g>
<set xlink:href="#test" attributeName="height" begin="2s" to="100" />
</g>
</switch>
<rect id="test" width="100" height="0" fill="green"/>
</svg>