Bug 491080: add support for xlink:href targeting of SVG (SMIL) animations. r+sr=roc

This commit is contained in:
Daniel Holbert 2009-07-15 21:20:16 -07:00
Родитель 73a268beee
Коммит 6b50542ae3
12 изменённых файлов: 256 добавлений и 20 удалений

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

@ -49,16 +49,29 @@
NS_IMPL_ADDREF_INHERITED(nsSVGAnimationElement, nsSVGAnimationElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGAnimationElement, nsSVGAnimationElementBase)
NS_INTERFACE_MAP_BEGIN(nsSVGAnimationElement)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGAnimationElement)
NS_INTERFACE_MAP_ENTRY(nsISMILAnimationElement)
NS_INTERFACE_MAP_ENTRY(nsIDOMElementTimeControl)
NS_INTERFACE_MAP_END_INHERITING(nsSVGAnimationElementBase)
// Cycle collection magic -- based on nsSVGUseElement
NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGAnimationElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsSVGAnimationElement,
nsSVGAnimationElementBase)
tmp->mHrefTarget.Unlink();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsSVGAnimationElement,
nsSVGAnimationElementBase)
tmp->mHrefTarget.Traverse(&cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
//----------------------------------------------------------------------
// Implementation
nsSVGAnimationElement::nsSVGAnimationElement(nsINodeInfo *aNodeInfo)
: nsSVGAnimationElementBase(aNodeInfo),
mHrefTarget(this),
mTimedDocumentRoot(nsnull)
{
}
@ -100,17 +113,13 @@ nsIContent*
nsSVGAnimationElement::GetTargetElementContent()
{
if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
// XXXdholbert: Use xlink:href attr to look up target element here.
// Note: Need to check for updated target element each sample, because
// the existing target's ID might've changed, or another element
// with the same ID might've been inserted earlier in the DOM tree.
NS_NOTYETIMPLEMENTED("nsSVGAnimationElement::GetTargetElementContent for "
"xlink:href-targeted animations");
return nsnull;
return mHrefTarget.get();
}
NS_ABORT_IF_FALSE(!mHrefTarget.get(),
"We shouldn't have an xlink:href target "
"if we don't have an xlink:href attribute");
// No "xlink:href" attribute --> target is my parent.
// No "xlink:href" attribute --> I should target my parent.
return nsSVGUtils::GetParentElement(this);
}
@ -223,6 +232,9 @@ nsSVGAnimationElement::BindToTree(nsIDocument* aDocument,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers)
{
NS_ABORT_IF_FALSE(!mHrefTarget.get(),
"Shouldn't have href-target yet "
"(or it should've been cleared)");
nsresult rv = nsSVGAnimationElementBase::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
@ -252,6 +264,17 @@ nsSVGAnimationElement::BindToTree(nsIDocument* aDocument,
if (controller) {
controller->RegisterAnimationElement(this);
}
const nsAttrValue* href = mAttrsAndChildren.GetAttr(nsGkAtoms::href,
kNameSpaceID_XLink);
if (href) {
nsAutoString hrefStr;
href->ToString(hrefStr);
// Pass in |aParent| instead of |this| -- first argument is only used
// for a call to GetCurrentDoc(), and |this| might not have a current
// document yet.
UpdateHrefTarget(aParent, hrefStr);
}
}
AnimationNeedsResample();
@ -274,6 +297,8 @@ nsSVGAnimationElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
mTimedDocumentRoot = nsnull;
}
mHrefTarget.Unlink();
AnimationNeedsResample();
nsSVGAnimationElementBase::UnbindFromTree(aDeep, aNullParent);
@ -319,8 +344,17 @@ nsSVGAnimationElement::ParseAttribute(PRInt32 aNamespaceID,
}
}
return nsSVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
aValue, aResult);
PRBool returnVal =
nsSVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
aValue, aResult);
if (aNamespaceID == kNameSpaceID_XLink &&
aAttribute == nsGkAtoms::href &&
IsInDoc()) {
// NOTE: If we fail the IsInDoc call, it's ok -- we'll update the target
// on next BindToTree call.
UpdateHrefTarget(this, aValue);
}
return returnVal;
}
nsresult
@ -336,6 +370,10 @@ nsSVGAnimationElement::UnsetAttr(PRInt32 aNamespaceID,
mTimedElement.UnsetAttr(aAttribute)) {
AnimationNeedsResample();
}
} else if (aNamespaceID == kNameSpaceID_XLink) {
if (aAttribute == nsGkAtoms::href) {
mHrefTarget.Unlink();
}
}
return NS_OK;
@ -395,3 +433,14 @@ nsSVGAnimationElement::EndElementAt(float offset)
return rv;
}
void
nsSVGAnimationElement::UpdateHrefTarget(nsIContent* aNodeForContext,
const nsAString& aHrefStr)
{
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI),
aHrefStr, GetOwnerDoc(), baseURI);
mHrefTarget.Reset(aNodeForContext, targetURI);
}

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

@ -41,6 +41,7 @@
#include "nsSVGElement.h"
#include "nsAutoPtr.h"
#include "nsReferencedElement.h"
#include "nsIDOMSVGAnimationElement.h"
#include "nsIDOMElementTimeControl.h"
#include "nsISMILAnimationElement.h"
@ -61,6 +62,9 @@ protected:
public:
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsSVGAnimationElement,
nsSVGAnimationElementBase)
NS_DECL_NSIDOMSVGANIMATIONELEMENT
NS_DECL_NSIDOMELEMENTTIMECONTROL
@ -91,6 +95,30 @@ public:
virtual nsSMILTimeContainer* GetTimeContainer();
protected:
void UpdateHrefTarget(nsIContent* aNodeForContext,
const nsAString& aHrefStr);
class TargetReference : public nsReferencedElement {
public:
TargetReference(nsSVGAnimationElement* aAnimationElement) :
mAnimationElement(aAnimationElement) {}
protected:
// We need to be notified when target changes, in order to request a
// sample (which will clear animation effects from old target and apply
// them to the new target).
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
nsReferencedElement::ContentChanged(aFrom, aTo);
mAnimationElement->AnimationNeedsResample();
}
// We need to override IsPersistent to get persistent tracking (beyond the
// first time the target changes)
virtual PRBool IsPersistent() { return PR_TRUE; }
private:
nsSVGAnimationElement* const mAnimationElement;
};
TargetReference mHrefTarget;
nsSMILTimedElement mTimedElement;
nsSMILTimeContainer* mTimedDocumentRoot;
};

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

@ -2,8 +2,9 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(2.5, false)">
<!-- This test checks a basic animation with "xlink:href" targeting -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="theRect" x="15" y="15" width="200" height="50" fill="blue" />
<animate xlink:href="#theRect" attributeName="height"
from="50" to="200" begin="0s" dur="2s" fill="freeze"/>
<rect id="blueRect" x="15" y="15" width="200" height="100" fill="blue"/>
<animate xlink:href="#blueRect" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</svg>

До

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

После

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

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

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior when "xlink:href" is modified -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var anim = document.getElementById("anim");
anim.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#blueRect");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="redRect" x="15" y="15" width="200" height="100" fill="red"/>
<rect id="blueRect" x="15" y="15" width="200" height="100" fill="blue"/>
<animate id="anim" xlink:href="#redRect" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</svg>

После

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

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

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(2.5, false)">
<!-- This test checks our behavior with animations that target nodes
other than their parents. -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect id="blueRect" x="15" y="15" width="200" height="100" fill="blue"/>
<animate id="anim" xlink:href="#redRect" attributeName="height"
to="0" begin="0s" dur="2s" fill="freeze"/>
<rect id="redRect" x="15" y="215" width="200" height="100" fill="red">
<animate id="anim" xlink:href="#blueRect" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</rect>
</svg>

После

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

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

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior with animations that are initially
href-targeted, but lose their href attribute. -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var anim = document.getElementById("anim");
anim.removeAttributeNS("http://www.w3.org/1999/xlink", "href");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="blueRect" x="15" y="15" width="200" height="100" fill="blue">
<animate id="anim" xlink:href="#redRect" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</rect>
<rect id="redRect" x="15" y="215" width="200" height="0" fill="red"/>
</svg>

После

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

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

@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior with animations that initially
have no 'xlink:href' attribute, but receive one via scripting. -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var anim = document.getElementById("anim");
anim.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#blueRect");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="blueRect" x="15" y="15" width="200" height="100" fill="blue">
</rect>
<rect id="redRect" x="15" y="215" width="200" height="0" fill="red">
<animate id="anim" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</rect>
</svg>

После

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

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

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior with an 'xlink:href'-targeted animation
when the target's ID is changed (which makes it no longer the target) -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var rect = document.getElementById("blueRect");
rect.setAttributeNS(null, "id", "differentBlueRect");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue"/>
<animate id="anim" xlink:href="#blueRect" attributeName="height"
to="0" begin="0s" dur="2s" fill="freeze"/>
</svg>

После

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

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

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior with an 'xlink:href'-targeted animation
when the target's ID is removed (which makes it no longer the target) -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var rect = document.getElementById("blueRect");
rect.removeAttributeNS(null, "id");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="blueRect" x="15" y="15" width="200" height="200" fill="blue"/>
<animate id="anim" xlink:href="#blueRect" attributeName="height"
to="0" begin="0s" dur="2s" fill="freeze"/>
</svg>

После

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

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

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior with an 'xlink:href'-targeted animation
when an earlier node suddenly obtains the target ID string (thereby
becoming the new animation target). -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var rect = document.getElementById("myLaterRect");
rect.setAttributeNS(null, "id", "myRect");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="myLaterRect" x="15" y="15" width="200" height="0" fill="blue"/>
<rect id="myRect" x="15" y="215" width="200" height="0" fill="red"/>
<animate id="anim" xlink:href="#myRect" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</svg>

После

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

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

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="go()">
<!-- This test checks our behavior with an 'xlink:href'-targeted animation
where there's initially no matching target, but then an element's ID is
set to match (making it the target) -->
<script xlink:href="smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function go() {
var rect = document.getElementById("rect");
rect.setAttributeNS(null, "id", "blueRect");
setTimeAndSnapshot(2.5, false)
}
</script>
<rect id="rect" x="15" y="15" width="200" height="100" fill="blue"/>
<animate id="anim" xlink:href="#blueRect" attributeName="height"
to="200" begin="0s" dur="2s" fill="freeze"/>
</svg>

После

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

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

@ -69,16 +69,25 @@ fails == anim-fillopacity-1.svg anim-standard-ref.svg # non-length-numeric va
== 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-3.svg anim-standard-ref.svg
== 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-5.svg anim-standard-ref.svg
== anim-retarget-6.svg anim-standard-ref.svg
== anim-retarget-7.svg anim-standard-ref.svg
== 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
== anim-targethref-1.svg anim-standard-ref.svg
== anim-targethref-2.svg anim-standard-ref.svg
== anim-targethref-3.svg anim-standard-ref.svg
== anim-targethref-4.svg anim-standard-ref.svg
== anim-targethref-5.svg anim-standard-ref.svg
== anim-targethref-6.svg anim-standard-ref.svg
== anim-targethref-7.svg anim-standard-ref.svg
== anim-targethref-8.svg anim-standard-ref.svg
== anim-targethref-9.svg anim-standard-ref.svg
== anim-width-done-1a.svg anim-standard-ref.svg
== anim-width-done-1b.svg anim-standard-ref.svg