Bug 481562: Don't create time container for an <svg> element until after it's been bound to a smil-enabled document. r+sr=roc

This commit is contained in:
Daniel Holbert 2009-03-07 13:40:08 -08:00
parent a5b835b377
commit 3f4092e862
11 changed files with 340 additions and 17 deletions

View File

@ -1321,15 +1321,26 @@ nsSVGSVGElement::BindToTree(nsIDocument* aDocument,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers)
{
PRBool outermost = WillBeOutermostSVG(aParent, aBindingParent);
nsSMILAnimationController* smilController = nsnull;
if (!mTimedDocumentRoot && outermost) {
// We will now be the outermost SVG element
mTimedDocumentRoot = new nsSMILTimeContainer();
NS_ENSURE_TRUE(mTimedDocumentRoot, NS_ERROR_OUT_OF_MEMORY);
} else if (!outermost) {
mTimedDocumentRoot = nsnull;
mStartAnimationOnBindToTree = PR_TRUE;
if (aDocument) {
smilController = aDocument->GetAnimationController();
if (smilController) {
// SMIL is enabled in this document
if (WillBeOutermostSVG(aParent, aBindingParent)) {
// We'll be the outermost <svg> element. We'll need a time container.
if (!mTimedDocumentRoot) {
mTimedDocumentRoot = new nsSMILTimeContainer();
NS_ENSURE_TRUE(mTimedDocumentRoot, NS_ERROR_OUT_OF_MEMORY);
}
} else {
// We're a child of some other <svg> element, so we don't need our own
// time container. However, we need to make sure that we'll get a
// kick-start if we get promoted to be outermost later on.
mTimedDocumentRoot = nsnull;
mStartAnimationOnBindToTree = PR_TRUE;
}
}
}
nsresult rv = nsSVGSVGElementBase::BindToTree(aDocument, aParent,
@ -1337,14 +1348,8 @@ nsSVGSVGElement::BindToTree(nsIDocument* aDocument,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv,rv);
if (mTimedDocumentRoot) {
if (aDocument) {
nsSMILAnimationController* smilController =
aDocument->GetAnimationController();
if (smilController) {
rv = mTimedDocumentRoot->SetParent(smilController);
}
}
if (mTimedDocumentRoot && smilController) {
rv = mTimedDocumentRoot->SetParent(smilController);
if (mStartAnimationOnBindToTree) {
mTimedDocumentRoot->Begin();
}
@ -1362,7 +1367,6 @@ nsSVGSVGElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
nsSVGSVGElementBase::UnbindFromTree(aDeep, aNullParent);
}
#endif // MOZ_SMIL
//----------------------------------------------------------------------

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Deferred tree</title>
</head>
<body>
<p id="tree-container"/>
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px"
id="created-svg">
<rect x="0" y="0" width="199" height="199"
style="fill: none; stroke: black"/>
<ellipse stroke-width="1" stroke="black" fill="yellow" cx="100"
cy="20" rx="40" ry="20"/>
</svg>
</body>
</html>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<title>Deferred tree</title>
<!--
PURPOSE: If a SVG subdocument is created dynamically, any timing-related
animation API calls on the subdocument should silently fail until it's
been attached to a document.
OPERATION: We start with a plain XHTML document, but later a div and an SVG
subdocument are created. We attempt an animation API call on the SVG
element before attaching it to the XHTML document.
EXPECTED RESULTS: The animation API call should have no effect.
-->
<script src="deferred-tree-util.js" type="text/javascript"/>
<script>
function animate()
{
// Set up
var div = makeDiv();
var svg = makeSvg();
var target = document.getElementById('tree-container');
// Make an animation api call (should have no effect, if we're sane)
svg.setCurrentTime(1.0);
// Trigger a "BindToTree" call on the SVG element
div.appendChild(svg);
// Finally, we attach to the document and pause animations.
target.appendChild(div);
// Reftest Snapshot
svg.pauseAnimations();
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="animate()">
<p id="tree-container"/>
</body>
</html>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<title>Deferred tree</title>
<!--
PURPOSE: If a SVG subdocument is created dynamically, any timing-related
animation API calls on the subdocument should silently fail until it's
been attached to a document.
OPERATION: We start with a plain XHTML document, but later a div and an SVG
subdocument are created. We attempt an animation API call on the SVG
element before attaching it to the XHTML document.
EXPECTED RESULTS: The animation API call should have no effect.
-->
<script src="deferred-tree-util.js" type="text/javascript"/>
<script>
function animate()
{
// Set up
var div = makeDiv();
var svg = makeSvg();
var target = document.getElementById('tree-container');
// Trigger a "BindToTree" call on the SVG element
div.appendChild(svg);
// Make an animation api call (should have no effect, if we're sane)
svg.setCurrentTime(1.0);
// Finally, we attach to the document and pause animations.
target.appendChild(div);
// Reftest Snapshot
svg.pauseAnimations();
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="animate()">
<p id="tree-container"/>
</body>
</html>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Deferred tree</title>
</head>
<body>
<p id="tree-container"/>
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px"
id="created-svg">
<rect x="0" y="0" width="199" height="199"
style="fill: none; stroke: black"/>
<ellipse stroke-width="1" stroke="black" fill="yellow" cx="100"
cy="95" rx="40" ry="20"/>
</svg>
</body>
</html>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<title>Deferred tree</title>
<script src="deferred-tree-util.js" type="text/javascript"/>
<script>
function animate()
{
// Set up
var div = makeDiv();
var svg = makeSvg();
var target = document.getElementById('tree-container');
div.appendChild(svg);
target.appendChild(div);
// These calls *should* have an effect, since they happen
// after 'svg' has been attached to the XHTML document.
svg.setCurrentTime(1.0);
svg.pauseAnimations();
// Reattach the SVG element to its parent div.
// (If we're sane, this shouldn't reset its time container.)
div.appendChild(svg);
// Reftest Snapshot
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="animate()">
<p id="tree-container"/>
</body>
</html>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<title>Deferred tree</title>
<script src="deferred-tree-util.js" type="text/javascript"/>
<script>
function animate()
{
// Set up
var div = makeDiv();
var svg = makeSvg();
var target = document.getElementById('tree-container');
div.appendChild(svg);
target.appendChild(div);
// These calls *should* have an effect, since they happen
// after 'svg' has been attached to the XHTML document.
svg.setCurrentTime(1.0);
svg.pauseAnimations();
// Shift the SVG element to its parent's parent.
// (If we're sane, this shouldn't reset its time container.)
target.appendChild(svg);
// Reftest Snapshot
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="animate()">
<p id="tree-container"/>
</body>
</html>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<title>Deferred tree</title>
<script src="deferred-tree-util.js" type="text/javascript"/>
<script>
function animate()
{
// Set up
var div = makeDiv();
var svg = makeSvg();
var target = document.getElementById('tree-container');
div.appendChild(svg);
target.appendChild(div);
// These calls *should* have an effect, since they happen
// after 'svg' has been attached to the XHTML document.
svg.setCurrentTime(1.0);
svg.pauseAnimations();
// Create another div container, and move svg element there
// (temporarily detaching it from the document), before attaching
// this new subtree back onto the document. Our current behavior
// (which matches Opera 9.64) is to preserve svg's time container
// through this manipulation.
div2 = makeDiv();
div2.appendChild(svg);
div.appendChild(div2);
// Reftest Snapshot
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="animate()">
<p id="tree-container"/>
</body>
</html>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<title>Deferred tree</title>
<script src="deferred-tree-util.js" type="text/javascript"/>
<script>
function animate()
{
// Set up
var div = makeDiv();
var svg = makeSvg();
var target = document.getElementById('tree-container');
div.appendChild(svg);
target.appendChild(div);
// Create another div container, and move svg element there
// (temporarily detaching it from the document).
div2 = makeDiv();
div2.appendChild(svg);
// These calls *should* have an effect, since they happen
// after 'svg' has been attached to the XHTML document (even though
// it's not currently attached)
svg.setCurrentTime(1.0);
svg.pauseAnimations();
// Attach the div2+svg subtree onto the document. Our current
// behavior (which matches Opera 9.64) is to preserve svg's time
// container through this manipulation.
div.appendChild(div2);
// Reftest Snapshot
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="animate()">
<p id="tree-container"/>
</body>
</html>

View File

@ -0,0 +1,39 @@
function makeDiv()
{
const xhtmlns="http://www.w3.org/1999/xhtml";
return document.createElementNS(xhtmlns, 'div');
}
function makeSvg()
{
const svgns="http://www.w3.org/2000/svg";
var svg = document.createElementNS(svgns, 'svg');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('width', '200px');
svg.setAttribute('height', '200px');
var rect = document.createElementNS(svgns, 'rect');
rect.setAttribute('x', '0');
rect.setAttribute('y', '0');
rect.setAttribute('width', '199');
rect.setAttribute('height', '199');
rect.setAttribute('style', 'fill: none; stroke: black');
var ellipse = document.createElementNS(svgns, 'ellipse');
ellipse.setAttribute('stroke-width', '1');
ellipse.setAttribute('stroke', 'black');
ellipse.setAttribute('fill', 'yellow');
ellipse.setAttribute('cx', '100');
ellipse.setAttribute('cy', '20');
ellipse.setAttribute('rx', '40');
ellipse.setAttribute('ry', '20');
var anim = document.createElementNS(svgns, 'animate');
anim.setAttribute('attributeName', 'cy');
anim.setAttribute('attributeType', 'XML');
anim.setAttribute('begin', '0s');
anim.setAttribute('from', '20');
anim.setAttribute('to', '170');
anim.setAttribute('dur', '2s');
ellipse.appendChild(anim);
svg.appendChild(rect);
svg.appendChild(ellipse);
return svg;
}

View File

@ -7,6 +7,12 @@ random == enveloped-tree-1.xhtml enveloped-tree-1-ref.xhtml # bug 470868
== moved-tree-1.xhtml moved-tree-1-ref.xhtml
== deferred-anim-1.xhtml deferred-anim-1-ref.xhtml
== deferred-tree-1.xhtml deferred-tree-1-ref.xhtml
== deferred-tree-2a.xhtml deferred-tree-2-ref.xhtml
== deferred-tree-2b.xhtml deferred-tree-2-ref.xhtml
== deferred-tree-3a.xhtml deferred-tree-3-ref.xhtml
== deferred-tree-3b.xhtml deferred-tree-3-ref.xhtml
== deferred-tree-3c.xhtml deferred-tree-3-ref.xhtml
== deferred-tree-3d.xhtml deferred-tree-3-ref.xhtml
# this will occasionally fail until we correctly clear animation effects from
# no-longer-targeted elements
random == invalid-elem-1.xhtml invalid-elem-1-ref.xhtml