Bug 491080: add support for xlink:href targeting of SVG (SMIL) animations. r+sr=roc
|
@ -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
|
||||
|
|