Bug 487450: Remove stale SMIL animation effects from SVG elements, when animations are dynamically removed or retargeted. r+sr=roc

This commit is contained in:
Daniel Holbert 2009-07-14 12:33:29 -07:00
Родитель 944e39a419
Коммит b47ea83e82
24 изменённых файлов: 469 добавлений и 33 удалений

Просмотреть файл

@ -82,6 +82,11 @@ public:
*/
virtual nsSMILValue GetBaseValue() const = 0;
/**
* Clears the animated value of this attribute.
*/
virtual void ClearAnimValue() = 0;
/**
* Sets the presentation value of this attribute.
*

Просмотреть файл

@ -262,6 +262,32 @@ nsSMILAnimationController::StopTimer()
//----------------------------------------------------------------------
// Sample-related methods and callbacks
PR_CALLBACK PLDHashOperator
RemoveCompositorFromTable(nsSMILCompositor* aCompositor,
void* aData)
{
nsSMILCompositorTable* lastCompositorTable =
static_cast<nsSMILCompositorTable*>(aData);
lastCompositorTable->RemoveEntry(aCompositor->GetKey());
return PL_DHASH_NEXT;
}
PR_CALLBACK PLDHashOperator
DoClearAnimationEffects(nsSMILCompositor* aCompositor,
void* /*aData*/)
{
aCompositor->ClearAnimationEffects();
return PL_DHASH_NEXT;
}
PR_CALLBACK PLDHashOperator
DoComposeAttribute(nsSMILCompositor* aCompositor,
void* /*aData*/)
{
aCompositor->ComposeAttribute();
return PL_DHASH_NEXT;
}
void
nsSMILAnimationController::DoSample()
{
@ -322,17 +348,19 @@ nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
// STEP 3: Remove animation effects from any no-longer-animated elems/attrs
if (mLastCompositorTable) {
// XXX Remove animation effects from no-longer-animated elements
// * For each compositor in current sample's hash table:
// - Remove entry from *prev sample's* hash table
// * For any entries still remaining in prev sample's hash table:
// - Remove animation from that entry's attribute.
// (For nsSVGLength2, set anim val = base val. For CSS attribs,
// just clear the relevant chunk of OverrideStyle)
// * For each compositor in current sample's hash table, remove entry from
// prev sample's hash table -- we don't need to clear animation
// effects of those compositors, since they're still being animated.
currentCompositorTable->EnumerateEntries(RemoveCompositorFromTable,
mLastCompositorTable);
// * For each entry that remains in prev sample's hash table (i.e. for
// every target that's no longer animated), clear animation effects.
mLastCompositorTable->EnumerateEntries(DoClearAnimationEffects, nsnull);
}
// STEP 4: Compose currently-animated attributes.
nsSMILCompositor::ComposeAttributes(*currentCompositorTable);
currentCompositorTable->EnumerateEntries(DoComposeAttribute, nsnull);
// Update last compositor table
mLastCompositorTable = currentCompositorTable.forget();

Просмотреть файл

@ -85,6 +85,19 @@ nsSMILCompositor::AddAnimationFunction(nsSMILAnimationFunction* aFunc)
}
}
nsISMILAttr*
nsSMILCompositor::CreateSMILAttr()
{
if (mKey.mIsCSS) {
// XXX Look up style system for the CSS property. The set of CSS properties
// should be the same for all elements so we don't need to query the element
// itself.
} else {
return mKey.mElement->GetAnimatedAttr(mKey.mAttributeName);
}
return nsnull;
}
void
nsSMILCompositor::ComposeAttribute()
{
@ -93,15 +106,7 @@ nsSMILCompositor::ComposeAttribute()
// FIRST: Get the nsISMILAttr (to grab base value from, and to eventually
// give animated value to)
nsAutoPtr<nsISMILAttr> smilAttr;
if (mKey.mIsCSS) {
// XXX Look up style system for the CSS property. The set of CSS properties
// should be the same for all elements so we don't need to query the element
// itself.
} else {
smilAttr = mKey.mElement->GetAnimatedAttr(mKey.mAttributeName);
}
nsAutoPtr<nsISMILAttr> smilAttr(CreateSMILAttr());
if (!smilAttr) {
// Target attribute not found
return;
@ -163,16 +168,17 @@ nsSMILCompositor::ComposeAttribute()
}
}
/*static*/ void
nsSMILCompositor::ComposeAttributes(nsSMILCompositorTable& aCompositorTable)
void
nsSMILCompositor::ClearAnimationEffects()
{
aCompositorTable.EnumerateEntries(DoComposeAttribute, nsnull);
if (!mKey.mElement || !mKey.mAttributeName)
return;
nsAutoPtr<nsISMILAttr> smilAttr(CreateSMILAttr());
if (!smilAttr) {
// Target attribute not found (or, out of memory)
return;
}
smilAttr->ClearAnimValue();
}
/*static*/ PR_CALLBACK PLDHashOperator
nsSMILCompositor::DoComposeAttribute(nsSMILCompositor* aCompositor,
void* /*aData*/)
{
aCompositor->ComposeAttribute();
return PL_DHASH_NEXT;
}

Просмотреть файл

@ -94,17 +94,21 @@ public:
// Adds the given animation function to this Compositor's list of functions
void AddAnimationFunction(nsSMILAnimationFunction* aFunc);
// Calls ComposeAttribute() on each nsSMILCompositor in the given hashset
static void ComposeAttributes(nsSMILCompositorTable& aCompositorTable);
// Composes the attribute's current value with the list of animation
// functions, and assigns the resulting value to this compositor's target
// attribute
void ComposeAttribute();
// Clears animation effects on my target attribute
void ClearAnimationEffects();
// Cycle-collection support
void Traverse(nsCycleCollectionTraversalCallback* aCallback);
private:
// Composes the attribute's current value with the list of animation
// functions, and assigns the resulting value to this compositor's target
// attribute.
void ComposeAttribute();
// Create a nsISMILAttr for my target, on the heap. Caller is responsible
// for deallocating the returned object.
nsISMILAttr* CreateSMILAttr();
// Static callback methods
PR_STATIC_CALLBACK(PLDHashOperator) DoComposeAttribute(

Просмотреть файл

@ -494,6 +494,15 @@ nsSVGLength2::SMILLength::GetBaseValue() const
return val;
}
void
nsSVGLength2::SMILLength::ClearAnimValue()
{
if (mVal->mIsAnimated) {
mVal->SetAnimValue(mVal->mBaseVal, mSVGElement);
mVal->mIsAnimated = PR_FALSE;
}
}
nsresult
nsSVGLength2::SMILLength::SetAnimValue(const nsSMILValue& aValue)
{

Просмотреть файл

@ -284,6 +284,7 @@ private:
const nsISMILAnimationElement* aSrcElement,
nsSMILValue &aValue) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
};
#endif // MOZ_SMIL

Просмотреть файл

@ -108,6 +108,14 @@ nsSVGTransformSMILAttr::GetBaseValue() const
return val;
}
void
nsSVGTransformSMILAttr::ClearAnimValue()
{
mVal->WillModify(nsISVGValue::mod_other);
mVal->mAnimVal = nsnull;
mVal->DidModify(nsISVGValue::mod_other);
}
nsresult
nsSVGTransformSMILAttr::SetAnimValue(const nsSMILValue& aValue)
{

Просмотреть файл

@ -63,6 +63,7 @@ public:
const nsISMILAnimationElement* aSrcElement,
nsSMILValue& aValue) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
protected:

Просмотреть файл

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we delete an <animate> node while its animation is in
progress. We verify that animation effects are removed from its former
target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var anim = document.getElementById("anim");
anim.parentNode.removeChild(anim);
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 862 B

Просмотреть файл

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we delete an <animate> node after its animation is
completed & frozen. We verify that animation effects are removed from its
former target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
anim.parentNode.removeChild(anim);
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 871 B

Просмотреть файл

@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we delete an <animate> node while its animation is in
progress. We verify that animation effects are removed from its former
target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var anim = document.getElementById("anim");
anim.parentNode.removeChild(anim);
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue"/>
<animate id="anim" xlink:href="#blueRect" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 886 B

Просмотреть файл

@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we delete an <animate> node after its animation is
completed & frozen. We verify that animation effects are removed from its
former target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
anim.parentNode.removeChild(anim);
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue"/>
<animate id="anim" xlink:href="#blueRect" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 895 B

Просмотреть файл

@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we remove an animation element's "attributeName"
attribute, which invalidates a completed, frozen animation. We verify
that animation effects are removed from the previously-targeted
attribute. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
anim.removeAttributeNS(null, "attributeName");
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="x"
begin="0s" dur="2s" by="100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 943 B

Просмотреть файл

@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we change an animation element's "attributeType" attribute
to "CSS", which invalidates a completed, frozen animation (since in SVG,
there's no CSS property that matches the attributeName that we're
animating, "x"). We verify that animation effects are removed from the
previously-targeted attribute. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
anim.setAttributeNS(null, "attributeType", "CSS");
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="x"
begin="0s" dur="2s" by="100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we change an animation element's "by" attribute to an
invalid value. We verify that animation effects are removed from the
previously-targeted attribute. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
anim.setAttributeNS(null, "by", "invalid value that can't be added");
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="x"
begin="0s" dur="2s" by="100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 918 B

Просмотреть файл

@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we move an in-progress animation from one parent to
another. We verify that animation effects are removed from the old
parent and are applied to the new parent. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var anim = document.getElementById("anim");
var redRect = document.getElementById("redRect");
redRect.appendChild(anim);
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="redRect" x ="15" y="15" width="200" height="250" fill="red"/>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we move a completed & frozen animation from one parent to
another. We verify that animation effects are removed from the old
parent and are applied to the new parent. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
var redRect = document.getElementById("redRect");
redRect.appendChild(anim);
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="redRect" x ="15" y="15" width="200" height="300" fill="red"/>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we retarget an in-progress animation from one target to
another. We verify that animation effects are removed from the old
target and are applied to the new target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var anim = document.getElementById("anim");
anim.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#redRect");
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="redRect" x="15" y="15" width="200" height="250" fill="red"/>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue"/>
<animate id="anim" xlink:href="#blueRect" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we remove the "xlink:href" attribute on an in-progress
animation, changing it to target its parent. We verify that animation
effects are removed from the old target and are applied to the new
target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var anim = document.getElementById("anim");
anim.removeAttributeNS("http://www.w3.org/1999/xlink", "href");
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="redRect" x="15" y="15" width="200" height="250" fill="red">
<animate id="anim" xlink:href="#blueRect" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</rect>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we add an "xlink:href" attribute to an in-progress
animation, changing it to no longer target its parent. We verify that
animation effects are removed from the old target and are applied to the
new target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var anim = document.getElementById("anim");
anim.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#redRect");
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="redRect" x="15" y="15" width="200" height="250" fill="red"/>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue">
<animate id="anim" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we tweak an element's "id" attribute, which retargets an
in-progress animation to that element. We verify that animation effects
are removed from the old target and are applied to the new target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(0.5);
var newTarget = document.getElementById("newTarget");
newTarget.setAttributeNS(null, "id", "target");
setTimeAndSnapshot(1, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="newTarget" x="15" y="15" width="200" height="250" fill="red"/>
<rect id="target" x="15" y="15" width="200" height="200" fill="blue"/>
<animate id="anim" xlink:href="#target" attributeName="height"
begin="0s" dur="2s" by="-100" fill="freeze"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we remove an element's "id" attribute, which retargets a
completed, frozen animation from that element to another. We verify
that animation effects are removed from the old target and are applied
to the new target. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var newTarget = document.getElementById("target");
newTarget.removeAttributeNS(null, "id");
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="target" x="15" y="15" width="200" height="200" fill="red"/>
<rect id="target" x="15" y="15" width="200" height="100" fill="blue"/>
<animate id="anim" xlink:href="#target" attributeName="height"
begin="0s" dur="2s" by="100" fill="freeze"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="go()">
<!-- In this test, we change an animation element's "attributeName"
attribute, which retargets a completed, frozen animation from one
attribute to another. We verify that animation effects are removed from
the old attribute and are applied to the new one. -->
<script>
function go() {
// Seek animation before we start tweaking things, to make sure we've
// already started sampling it.
document.documentElement.setCurrentTime(2.0);
var anim = document.getElementById("anim");
anim.setAttributeNS(null, "attributeName", "height");
setTimeAndSnapshot(2.5, false);
}
</script>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect x="15" y="15" width="200" height="100" fill="blue">
<animate id="anim" attributeName="x"
begin="0s" dur="2s" by="100" fill="freeze"/>
</rect>
</svg>

После

Ширина:  |  Высота:  |  Размер: 993 B

Просмотреть файл

@ -12,6 +12,8 @@
# - DOM interfaces:
# * Section 6.2 of http://www.w3.org/TR/smil-animation/
# * Animation-related bits of http://www.w3.org/TR/SVG/struct.html#DOMInterfaces
# - Some more "anim-retarget" tests, with attributeType being changed/cleared.
# (after we've got support for SVG/SMIL animation of CSS properties)
# animation sort-order tests
include sort/reftest.list
@ -58,6 +60,22 @@ fails == anim-fillopacity-1.svg anim-standard-ref.svg # non-length-numeric va
== anim-height-interp-5.svg anim-height-interp-5-ref.svg
== anim-height-interp-6.svg anim-height-interp-6-ref.svg
== anim-remove-1.svg anim-standard-ref.svg
== anim-remove-2.svg anim-standard-ref.svg
== anim-remove-3.svg anim-standard-ref.svg
== anim-remove-4.svg anim-standard-ref.svg
== anim-remove-5.svg anim-standard-ref.svg
== anim-remove-6.svg anim-standard-ref.svg
== anim-remove-7.svg anim-standard-ref.svg
== anim-retarget-1.svg anim-standard-ref.svg
== anim-retarget-2.svg anim-standard-ref.svg
fails == anim-retarget-3.svg anim-standard-ref.svg # href support
== anim-retarget-4.svg anim-standard-ref.svg
fails == anim-retarget-5.svg anim-standard-ref.svg # href support
fails == anim-retarget-6.svg anim-standard-ref.svg # href support
fails == anim-retarget-7.svg anim-standard-ref.svg # href support
== anim-retarget-8.svg anim-standard-ref.svg
fails == anim-strokecolor-1.svg anim-standard-ref.svg # color support
fails == anim-strokewidth-1.svg anim-standard-ref.svg # color support
fails == anim-targethref-1.svg anim-standard-ref.svg # href support