Bug 81792 (smil_with_uses) - Triggering an animation in cloned (uses) object causes all other cloned objects to animate
Summary: Triggering an animation in cloned (uses) object causes all other cloned objec...
Status: UNCONFIRMED
Alias: smil_with_uses
Product: WebKit
Classification: Unclassified
Component: SVG (show other bugs)
Version: 528+ (Nightly build)
Hardware: PC Windows XP
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-03-21 09:11 PDT by David White
Modified: 2012-03-23 07:04 PDT (History)
2 users (show)

See Also:


Attachments
SVG with an animation on a object that is cloned with uses. Mouseover on circles should just cause single element to animate but instead it all animates. Ignore the ripple, just appreciate it :-) (387.68 KB, image/svg+xml)
2012-03-21 09:11 PDT, David White
no flags Details
New and simpler test case (3.08 KB, image/svg+xml)
2012-03-23 02:04 PDT, David White
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description David White 2012-03-21 09:11:50 PDT
Created attachment 133056 [details]
SVG with an animation on a object that is cloned with uses. Mouseover on circles should just cause single element to animate but instead it all animates. Ignore the ripple, just appreciate it :-)

Triggering an animation in an SVG element that is cloned with uses should cause all clones to animate. However, triggering that animation in a uses clone (rather the element that was cloned) should only animate the clone.

To replicate this bug
1. create a circle and add a SMIL animation on mouseover.
2. Clone this circle several times with uses
3. hide the original circle in a hidden group.
4. Test the SVG. Putting mouse cursor over a single

What should happen?
A single clone should animate when the mouse cursor is over it. The other clones should not.

What does happen?
All the circles animate when the mouse cursor is over a single one, in spite of the animation not being triggered in the original object (it's not displayed).
Comment 1 Nikolas Zimmermann 2012-03-22 03:27:58 PDT
Hi David, thanks a lot for the testcase and bug report.
Unfortunately this is not debuggable as-is, the SVG is way too complex. Could you upload another testcase, as simple as possible, that highlights the problem. This raises the chances that someone looks at it quickly.
Comment 2 David White 2012-03-23 02:04:23 PDT
Created attachment 133445 [details]
New and simpler test case

This is a simpler test case. The black circle top left (path4011) has an animateTransform on mouseover and is cloned three times (<use>) to create the green, blue and red circles.

Mouseover on a coloured circle animates that circle but all others do as well. Just the one circle should animate. (Try with Firefox - dare I say that?)

What is unclear is what should happen when mouseover on the black circle. I would say that all circles should animate since they should mimic the change in properties of the original. However, that is not what Firefox does. I would be interested to have your opinion on this.
Comment 3 David White 2012-03-23 02:17:41 PDT
Behaviour for part of this bug report is not clear (what happens when triggering an animation in an element which is cloned with <use> - do clones animate).

Since Firefox didn't do what I expected as well in this test case I felt I should raise it as a bug to get agreement on what should really happen, or we're going to get the key browsers doing different things. See https://bugzilla.mozilla.org/show_bug.cgi?id=738574
Comment 4 David White 2012-03-23 02:54:12 PDT
My understanding is now that "Animations on a referenced element will cause the instances to also be animated." so Firefox and webkit both wrong on that aspect.

http://www.w3.org/TR/SVG11/struct.html#UseElement
Comment 5 Nikolas Zimmermann 2012-03-23 04:27:32 PDT
(In reply to comment #4)
> My understanding is now that "Animations on a referenced element will cause the instances to also be animated." so Firefox and webkit both wrong on that aspect.
> 
> http://www.w3.org/TR/SVG11/struct.html#UseElement


You misunderstood parts of the <use> element.

    <path id="path4011".../>
      <animateTransform
         to="1"
         from="2"
         type="scale"
         dur="1s"
         begin="mouseover"
         attributeName="transform"
         id="animateTransform7986" />
    </path>
    <use y="10" xlink:href="#path4011"...
    <use y="100" xlink:href="#path4011"...
    <use y="200" xlink:href="#path4011"...

What you expect is that when moving the mouse over an "instance", only that specific instance should get animated - I got that. Though using this construct this can't work.

You have to attach this animateTransform to the individual <use> elements, either as child of the <use> element or targeting the use element via xlink:href. Otherwise you'll always end up animating all instances of your path.

Imagine you're changing the "d" attribute of the path from JavaScript. What do you expect? All instances immediately reflect the change -- the same is true for SMIL animations here.
Comment 6 Nikolas Zimmermann 2012-03-23 04:29:14 PDT
(In reply to comment #3)
> Behaviour for part of this bug report is not clear (what happens when triggering an animation in an element which is cloned with <use> - do clones animate).
> 
> Since Firefox didn't do what I expected as well in this test case I felt I should raise it as a bug to get agreement on what should really happen, or we're going to get the key browsers doing different things. See https://bugzilla.mozilla.org/show_bug.cgi?id=738574

I can't comment on the Mozilla bug, but their state resolution is wrong. They made this a duplicate of bug 619509, which is about:
"then that 'set' should be triggered simultaneously for the original and for *all* of its clones, whenever *any* of them is hovered.  (because events are supposed to be propagated to all of them)  This doesn't work currently."

That works for us, and your testcase just proofs that. If it also works in Mozilla, their bug shall be closed as well :-)
Comment 7 David White 2012-03-23 05:54:23 PDT
Thank you for getting back to me, Nikolas,

Unfortunately Webkit and FF are doing this different, which is a big concern. You said:

"You have to attach this animateTransform to the individual <use> elements, either as child of the <use> element or targeting the use element via xlink:href. Otherwise you'll always end up animating all instances of your path.

Imagine you're changing the "d" attribute of the path from JavaScript. What do you expect? All instances immediately reflect the change -- the same is true for SMIL animations here."

The spec states that:
"The effect of a ‘use’ element is as if the contents of the referenced element were deeply cloned into a separate non-exposed DOM tree which had the ‘use’ element as its parent and all of the ‘use’ element's ancestors as its higher-level ancestors"

My point is that because <use> does a "deep clone" of the referenced element, that means that the animateTransform is also copied and since the begin and end attributes of those copies do not reference an ID explicitly, those copied animateTransforms animate each cloned non-exposed DOM tree separately.

So, mouseover on the cloned element causes an event which bubbles up through the cloned tree and on through the parents. Since a referenced element cannot have a clone of itself as a child element, the event doesn't go anywhere near the referenced element. The only animateTransform that can pick up the event is the one in the non-exposed DOM tree - i.e. the cloned animateTransform. This means that the cloned path should animate and nothing else.

mouseover happens to the cloned elements - like you say it is analogous to setting a property. Using your analogy, it's like setting the fill colour on a <use> element as per my SVG example - you wouldn't expect everything including the referenced object to change colour. Yet that is what is happening with animation.
Comment 8 Nikolas Zimmermann 2012-03-23 06:07:46 PDT
(In reply to comment #7)
> Thank you for getting back to me, Nikolas,
> 
> Unfortunately Webkit and FF are doing this different, which is a big concern. You said:
Your example works the same in Opera & FF and WebKit, when hovering over a colored shape?
Can you summarize what we do differently than others? Is the black circle handling different?

> The spec states that:
> "The effect of a ‘use’ element is as if the contents of the referenced element were deeply cloned into a separate non-exposed DOM tree which had the ‘use’ element as its parent and all of the ‘use’ element's ancestors as its higher-level ancestors"
> 
> My point is that because <use> does a "deep clone" of the referenced element, that means that the animateTransform is also copied and since the begin and end attributes of those copies do not reference an ID explicitly, those copied animateTransforms animate each cloned non-exposed DOM tree separately.
It only states that the effect is-as it was deep cloned, there's no assumption that the actual implementation has to deep clone.
 
> So, mouseover on the cloned element causes an event which bubbles up through the cloned tree and on through the parents. Since a referenced element cannot have a clone of itself as a child element, the event doesn't go anywhere near the referenced element. The only animateTransform that can pick up the event is the one in the non-exposed DOM tree - i.e. the cloned animateTransform. This means that the cloned path should animate and nothing else.
Be careful here: the <use> element and its non-exposed "shadow tree" never receive events on their own. The events are dispatched to the SVGElementInstances, corresponding to the non-exposed elements in the shadow tree ("shadow tree" is our WebKit term, for naming non-exposed trees).

Implementation note:
In WebKit we do clone the referenced element of a <use> element and append it as non-exposed tree fragment to the <use> element _excluding_ any SMIL elements. We don't actually clone the animation* elements that may be present as children of the referenced element.

Instead we're detecting all instances of the <path> element, and animate them individually when an animation is running.

I have been tricked myself often when dealing with <use> event handling - it's not immediately obvious how it works together with SMIL animation.

Still I think the bug is invalid.
 
> mouseover happens to the cloned elements - like you say it is analogous to setting a property. Using your analogy, it's like setting the fill colour on a <use> element as per my SVG example - you wouldn't expect everything including the referenced object to change colour. Yet that is what is happening with animation.
Exactly, that's why I'm suggesting to attach the animation to the <use> element, not its target. Otherwise you're listening to any click of any of the instances, and each would trigger the animation, which is not what you want.
Comment 9 Nikolas Zimmermann 2012-03-23 06:15:17 PDT
Oops, I take that back. Both of your examples work as intended on FireFox nightlies (only the circle which is hovered is animated -- you said you've filed a FF bug for that? What's not working correctly on FF? I don't fully understand it).

Opera and WebKit have the same behavior (animation is triggered everywhere, whenever you hover an instance).
Comment 10 David White 2012-03-23 06:20:26 PDT
(In reply to comment #9)
> Oops, I take that back. Both of your examples work as intended on FireFox nightlies (only the circle which is hovered is animated -- you said you've filed a FF bug for that? What's not working correctly on FF? I don't fully understand it).
> 
> Opera and WebKit have the same behavior (animation is triggered everywhere, whenever you hover an instance).

Expected behaviour is that if you hover over the path (black), all should animate. But if you hover over a <use> (coloured) just that one animates.

What FF does wrong is that if you hover over the black just the black animates. The spec is very clear on this. "Animations on a referenced element will cause the instances to also be animated." That is the FF bug. What FF does right, I think, is just the one item animates if you hover over a <use>.

Comments to follow on cloning!
Comment 11 Nikolas Zimmermann 2012-03-23 06:28:17 PDT
(In reply to comment #10)
> Expected behaviour is that if you hover over the path (black), all should animate. But if you hover over a <use> (coloured) just that one animates.
> 
> What FF does wrong is that if you hover over the black just the black animates. The spec is very clear on this. "Animations on a referenced element will cause the instances to also be animated." That is the FF bug. What FF does right, I think, is just the one item animates if you hover over a <use>.
Okay, fair enough.

> Comments to follow on cloning!
I'm reopening this bug until its clear if Opera & us are right, or if FF is right (except their bug with the black shape, which is obviously wrong).
Comment 12 David White 2012-03-23 06:39:52 PDT
Nikolas,

We had a collision! I'll post what I was writing anyway in case that helps at all. Thanks again for looking at this.

-David.

> Implementation note:
> In WebKit we do clone the referenced element of a <use> element and append it as non-exposed tree fragment to the <use> element _excluding_ any SMIL elements. We don't actually clone the animation* elements that may be present as children of the referenced element.
> 
> Instead we're detecting all instances of the <path> element, and animate them individually when an animation is running.
> 
> I have been tricked myself often when dealing with <use> event handling - it's not immediately obvious how it works together with SMIL animation.
> 
> Still I think the bug is invalid.

My reading of http://www.w3.org/TR/SVG/struct.html#UseElement goes like this:


Quoting from the spec:
"The effect of a ‘use’ element is as if the contents of the referenced element were deeply cloned into a separate non-exposed DOM tree which had the ‘use’ element as its parent and all of the ‘use’ element's ancestors as its higher-level ancestors."

The whole contents  of the referenced element are cloned into the deep-copy, including all sub-elements and attributes. There's no allowance mentioned for leaving anything out, such as SMIL. The SMIL elements are part of the SVG document model so they must be copied as well.

From the spec:
"The event's target and currentTarget attributes are set to the SVGElementInstance that corresponds to the target and current target elements in the referenced subtree"

This is about event handling for the cloned tree, the "non-exposed tree". The SVGElementInstance is the instance in the non-exposed tree. Events raised in the context of the cloned instance are targetted at the cloned instance (SVGElementInstance) and therefore are not targeted at the referenced tree.

In my example SVG the mouseover event for a coloured circle must be targeted at the cloned elements and the SMIL object must be in the cloned element tree. Therefore that coloured circle should animate and the referenced object shouldn't.

However, for a mouseover event on the black circle. From the spec:
"Animations on a referenced element will cause the instances to also be animated."

So, if you trigger an animation on the referenced element, that is the situation when all cloned elements should animate.
Comment 13 David White 2012-03-23 06:44:30 PDT
Note: Now raised in Opera by Erik Dahlström as bug number CORE-45297.
Comment 14 Nikolas Zimmermann 2012-03-23 07:04:46 PDT
(In reply to comment #12)
> The whole contents  of the referenced element are cloned into the deep-copy, including all sub-elements and attributes. There's no allowance mentioned for leaving anything out, such as SMIL. The SMIL elements are part of the SVG document model so they must be copied as well.
Indeed, you're right. We probably got this wrong from the beginning.
It was meant as an optimization, to avoid having to run N animations, where one could animate all instances. But I see the problem now, and the cases where this fails, thanks for bringing this up!