Bug 21586 - SVG CSS properties don't work with CSS transitions
Summary: SVG CSS properties don't work with CSS transitions
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: 528+ (Nightly build)
Hardware: All OS X 10.5
: P2 Normal
Assignee: Dean Jackson
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-10-13 23:45 PDT by Jonathon Jongsma (jonner)
Modified: 2011-08-25 12:18 PDT (History)
11 users (show)

See Also:


Attachments
Work in progress patch (6.66 KB, patch)
2010-06-09 23:08 PDT, Rob Buis
no flags Details | Formatted Diff | Diff
Test with CSS transistions and SMIL Animation (455 bytes, image/svg+xml)
2010-06-10 04:28 PDT, Dirk Schulze
no flags Details
Not quite done patch (14.61 KB, patch)
2011-08-18 05:30 PDT, Dean Jackson
no flags Details | Formatted Diff | Diff
Patch (23.96 KB, patch)
2011-08-19 04:05 PDT, Dean Jackson
no flags Details | Formatted Diff | Diff
Patch (33.47 KB, patch)
2011-08-23 02:06 PDT, Dean Jackson
no flags Details | Formatted Diff | Diff
Patch (33.68 KB, patch)
2011-08-23 04:24 PDT, Dean Jackson
no flags Details | Formatted Diff | Diff
Patch (33.51 KB, patch)
2011-08-24 17:21 PDT, Dean Jackson
simon.fraser: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathon Jongsma (jonner) 2008-10-13 23:45:55 PDT
Trying to use CSS transitions with SVG content doesn't work with (at least some) CSS properties that seem like they should be animatable.
Comment 1 Dave Hyatt 2008-10-13 23:48:46 PDT
http://trac.webkit.org/changeset/37579

I added support for a few.

Comment 2 Rob Buis 2010-06-09 23:08:19 PDT
Created attachment 58332 [details]
Work in progress patch

I am adding this work-in-progress patch to get some feedback and because some things are still unclear.
What I tried were text-anchor, stroke-linejoin and stroke-linecap, those worked.
I then tried stroke-linewidth but there is a bug because it interpolates between two equal float values. Can this be because
the animation framework relies on PODs where here we use CSSValue pointers? I am basically not sure where RenderStyle *a
and *b come from. Note that this code is messy due to float <-> CSSValue* inconsistencies, but making that nicer could involve
changing RenderStyle.h/SVGRenderStyle.h a lot, which I want to prevent right now.
For the remaining SVG properties, I doubt some are very useful, like pointer-events. For properties that reference urls like
markers I am not sure how the smooth progress would go, I assume it is rather a sort of on/off switch. Finally I am not sure
how SVGPaint in stroke and fills should provide smooth progress, for instance when it starts with red paint but transforms to
some gradient? It would be great if this was documented somewhere, or if there already is a reference implementation.
Cheers,

Rob.
Comment 3 Dirk Schulze 2010-06-10 04:00:14 PDT
It's also the quastion how CSS transitions work together with SMIL animation? One value can be animated by both at te same time. Did someone test it?
Comment 4 Dirk Schulze 2010-06-10 04:28:14 PDT
Created attachment 58361 [details]
Test with CSS transistions and SMIL Animation

This is a quiete harmless test. But even this tests shows the problem. WebKit is jumping between the differnent animations (CSS and SVG Animation). Also results differ a bit between WebKit based browsers. On Gtk the opacity is between 0.5 and 0 all the time, oscilating from one to the other. Chromium animates from 1->0 than from 0 ->0.5 jumps to 1 and restarts the process. It should be tested what happens on additive sum, different animation functions and so on.
Comment 5 Simon Fraser (smfr) 2010-06-10 06:57:29 PDT
This describes which properties transition:
http://dev.w3.org/csswg/css3-transitions/#animatable-properties-

How SMIL and CSS animations interact is currently unspecified.
Comment 6 Simon Fraser (smfr) 2010-06-10 07:00:36 PDT
The patch looks reasonable, BTW.
Comment 7 Rob Buis 2010-06-10 07:23:47 PDT
Hello Simon,

(In reply to comment #5)
> This describes which properties transition:
> http://dev.w3.org/csswg/css3-transitions/#animatable-properties-
> 
> How SMIL and CSS animations interact is currently unspecified.

Thanks a lot! I was looking at the wrong spec then, it had no explanation about the SVG properties at all.
Cheers,

Rob.
Comment 8 Dirk Schulze 2010-08-17 01:12:52 PDT
(In reply to comment #6)
> The patch looks reasonable, BTW.

If I compare the list of animated SVG attributes (that can be set by CSS), with the list at http://dev.w3.org/csswg/css3-transitions/#animatable-properties, we can just use a few transitions in SVG, mainly some font-settings and the color-attribute/property. Means, even the current SVG attributes defined for transitions in http://trac.webkit.org/browser/trunk/WebCore/page/animation/AnimationBase.cpp#L677 are not allowed.

But maybe the spec can change in that way, not to define the property names, but define transitions by the data type, see: http://www.w3.org/TR/SVG/animate.html#Animatable
Comment 9 Dean Jackson 2010-08-17 09:39:10 PDT
You're right - the specification should define the animatable properties by datatype. This is my mistake.
Comment 10 Dirk Schulze 2010-08-18 10:35:11 PDT
How do we test CSS Transitions in DRT?
Comment 11 Simon Fraser (smfr) 2010-08-18 10:42:22 PDT
See LayoutTests/transitions
Comment 12 Eric Mill 2011-06-13 21:45:20 PDT
Is there any renewed interest in adding more supported attributes? "fill" is a big one, for example. 

I'm doing some SVG animations with Raphael, but using CSS animations for effects where possible makes things much faster, and makes more interesting work possible.
Comment 13 Dirk Schulze 2011-06-13 23:46:09 PDT
(In reply to comment #12)
> Is there any renewed interest in adding more supported attributes? "fill" is a big one, for example. 
> 
> I'm doing some SVG animations with Raphael, but using CSS animations for effects where possible makes things much faster, and makes more interesting work possible.

There is still a lot of interest in supporting more SVG-CSS values for CSS transitions and animations. Most SVG people are just busy with fixing other issues. So we are always searching for volunteers. Do you want to help? The attached patch should help to add more CSS properties, including fill and stroke. Just needs some testing. But I am sure we can help on testing.
Comment 14 Dean Jackson 2011-06-16 03:30:49 PDT
I updated Rob's patch recently but it is on a machine that is powered down on the other side of the world :) I plan to submit it for review next week. 

I was taking the approach that SMIL + CSS animations on the same property just don't mix. I think that's an ok situation for now.
Comment 15 Eric Mill 2011-06-16 12:44:54 PDT
(In reply to comment #13)
> There is still a lot of interest in supporting more SVG-CSS values for CSS transitions and animations. Most SVG people are just busy with fixing other issues. So we are always searching for volunteers. Do you want to help? The attached patch should help to add more CSS properties, including fill and stroke. Just needs some testing. But I am sure we can help on testing.

I've never done a Webkit patch before, but I might give it a shot. I might be more useful as a tester, though.
Comment 16 Dean Jackson 2011-08-18 05:30:02 PDT
Created attachment 104327 [details]
Not quite done patch

Attaching a not quite ready patch that can animate/transition SVG properties for opacity, length, colour and a few others. It will also transition fill and stroke paints as long as both ends of the animation are colours. I expect to finish this off today, then write tests.
(I notice there is a typo where the line-cap and line-join properties are referencing the wrong base)
Comment 17 Dirk Schulze 2011-08-19 00:01:47 PDT
Comment on attachment 104327 [details]
Not quite done patch

View in context: https://bugs.webkit.org/attachment.cgi?id=104327&action=review

General question: Do you respect fallback colors for fill and stroke? fill="url(#invalid) green" this should take a the solid color green.

> Source/WebCore/svg/SVGLength.h:141
> +            float fromPercent = from.valueAsPercentage();
> +            float toPercent = valueAsPercentage();
> +            length.newValueSpecifiedUnits(LengthTypePercentage, fromPercent + (toPercent - fromPercent) * progress, ec);

That means if you animate from cm to percentage, the calculated css value will be in percentage for the whole animation? That is different to SMIL animation, where we switch the unit type after 50% of the animation. If this is the way to go in CSS animations/transitions in general I'm fine. Should be discussed in publicFX as well.

> Source/WebCore/svg/SVGLength.h:145
> +            float fromValue = from.valueInSpecifiedUnits();
> +            float toValue = valueInSpecifiedUnits();
> +            length.newValueSpecifiedUnits(resultType, fromValue + (toValue - fromValue) * progress, ec);

Same like above.

> Source/WebCore/svg/SVGLength.h:152
> +

skip this line.
Comment 18 Dean Jackson 2011-08-19 04:05:28 PDT
Created attachment 104486 [details]
Patch
Comment 19 Dean Jackson 2011-08-19 04:12:51 PDT
Hi Dirk,

I didn't see this before I uploaded the most recent patch.

> General question: Do you respect fallback colors for fill and stroke? fill="url(#invalid) green" this should take a the solid color green.

I don't do anything here. If the style system resolves to give a Color to fill, then it can be transitioned (as long as the destination is also a Color). So in theory, this should work.

> > Source/WebCore/svg/SVGLength.h:141
> > +            float fromPercent = from.valueAsPercentage();
> > +            float toPercent = valueAsPercentage();
> > +            length.newValueSpecifiedUnits(LengthTypePercentage, fromPercent + (toPercent - fromPercent) * progress, ec);
> 
> That means if you animate from cm to percentage, the calculated css value will be in percentage for the whole animation? That is different to SMIL animation, where we switch the unit type after 50% of the animation. If this is the way to go in CSS animations/transitions in general I'm fine. Should be discussed in publicFX as well.

Yes, it should be discussed. In most cases we don't specify what should happen.
Comment 20 Dirk Schulze 2011-08-19 04:59:36 PDT
Comment on attachment 104486 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=104486&action=review

Some snippets and comments.

> LayoutTests/transitions/svg-transitions.html:35
> +    #rect2 {
> +      fill: rgb(0, 0, 255);
> +      stroke: rgb(255, 0, 0);
> +    }
> +    .animating #rect2 {
> +      fill: rgb(0, 255, 0);
> +      stroke: rgb(0, 0, 0);
> +    }

Can you add a test with fill: url(#invalid) green;  to fill: url(#invalid) blue; please? Even if does not pass at the beginning, or at least not animate.

> Source/WebCore/page/animation/AnimationBase.cpp:221
> +static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress)

Can you call it blendSVGLength?

> Source/WebCore/svg/SVGLength.h:125
> +        if (!from.isZero() && !isZero() && from.unitType() != unitType())
> +            return *this;

Why don't you allow animation between different unit types? We are doing it with SVGAnimatedLengthAnimator as well. You may need a new private value() function.

> Source/WebCore/svg/SVGLength.h:128
> +        if (from.isZero() && isZero())
> +            return *this;

You need an early return for LengthTypeUnknown as well, no?

> Source/WebCore/svg/SVGLength.h:140
> +        if (resultType == LengthTypePercentage) {
> +            float fromPercent = from.valueAsPercentage();
> +            float toPercent = valueAsPercentage();
> +            length.newValueSpecifiedUnits(LengthTypePercentage, fromPercent + (toPercent - fromPercent) * progress, ec);

Ah ok, animation between different unit types is difficult if one of the values is percentage since you need the viewport. You can still do it with animation between other unit types. But for percentage animation we need access to the SVGElement. I don't know another way to get the information about the viewPort :/
Comment 21 Dean Jackson 2011-08-22 16:27:13 PDT
(In reply to comment #19)

> > General question: Do you respect fallback colors for fill and stroke? fill="url(#invalid) green" this should take a the solid color green.
> 
> I don't do anything here. If the style system resolves to give a Color to fill, then it can be transitioned (as long as the destination is also a Color). So in theory, this should work.

I take this back. It's not so straightforward to handle this case. At the SVGRenderStyle level all we have is a paint type of SVG_PAINTTYPE_URI_RGBCOLOR, but we don't yet know if the URI is invalid.

I'm going to leave this type of paint out of the patch for now. We can add transitions of arbitrary paints later.
Comment 22 Dean Jackson 2011-08-23 02:06:35 PDT
Created attachment 104805 [details]
Patch
Comment 23 Dean Jackson 2011-08-23 02:08:10 PDT
Comment on attachment 104805 [details]
Patch

Removing review?. Forgot to add the test Dirk requested.
Comment 24 Dean Jackson 2011-08-23 04:24:28 PDT
Created attachment 104814 [details]
Patch
Comment 25 Dean Jackson 2011-08-23 04:30:20 PDT
(In reply to comment #20)
> (From update of attachment 104486 [details])

> Can you add a test with fill: url(#invalid) green;  to fill: url(#invalid) blue; please? Even if does not pass at the beginning, or at least not animate.

Done. It currently FAILs, as explained above.

> > Source/WebCore/page/animation/AnimationBase.cpp:221
> > +static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress)
> 
> Can you call it blendSVGLength?

The name 'blendFunc' is used for all the typed blending methods with parameter overloading.

> > Source/WebCore/svg/SVGLength.h:125
> > +        if (!from.isZero() && !isZero() && from.unitType() != unitType())
> > +            return *this;
> 
> Why don't you allow animation between different unit types? We are doing it with SVGAnimatedLengthAnimator as well. You may need a new private value() function.

Done. There are some restrictions. I can't currently animate between units that are relative (ems or exes). I can animate between percentages, but not between a percentage and not a percentage. There are also a couple of zero cases.

> 
> > Source/WebCore/svg/SVGLength.h:128
> > +        if (from.isZero() && isZero())
> > +            return *this;
> 
> You need an early return for LengthTypeUnknown as well, no?

Done.

> 
> > Source/WebCore/svg/SVGLength.h:140
> > +        if (resultType == LengthTypePercentage) {
> > +            float fromPercent = from.valueAsPercentage();
> > +            float toPercent = valueAsPercentage();
> > +            length.newValueSpecifiedUnits(LengthTypePercentage, fromPercent + (toPercent - fromPercent) * progress, ec);
> 
> Ah ok, animation between different unit types is difficult if one of the values is percentage since you need the viewport. You can still do it with animation between other unit types. But for percentage animation we need access to the SVGElement. I don't know another way to get the information about the viewPort :/

Right. We suffer the same problems in the non-SVG case, and if you find the bug about animating CSS gradients you see similar issues. I think this is a good start.
Comment 26 Dean Jackson 2011-08-23 04:33:09 PDT
(In reply to comment #25)
> I can animate between percentages, but not between a percentage and not a percentage. 

Err.. not overload, sorry.

% -> %,  YES
0 -> %, YES
% -> 0, YES
everything else -> %, NO
% -> everything else, NO
Comment 27 Nikolas Zimmermann 2011-08-24 06:35:03 PDT
Comment on attachment 104814 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=104814&action=review

Looks sane, still some comments from my side:

> Source/WebCore/svg/SVGLength.cpp:223
> +        break;

All these breaks can be removed.

> Source/WebCore/svg/SVGLength.cpp:255
> -    ASSERT_NOT_REACHED();
> +    ec = NOT_SUPPORTED_ERR;

This can stay as-is, it's not possible to reach this state.

> Source/WebCore/svg/SVGLength.cpp:271
>          break;

These breaks are superfluous now. you can remove them.

> Source/WebCore/svg/SVGLength.cpp:298
>      }
> +    ec = NOT_SUPPORTED_ERR;
> +    return 0;

Same as above, after removing all breaks; you can also reintroduce ASSERT_NOT_REACHED()  here, as it's not possible to have any other types than those handled in the switch. The compiler would warn about any missing, as there's no default: case.

> Source/WebCore/svg/SVGLength.h:142
> +            length.newValueSpecifiedUnits(LengthTypePercentage, fromPercent + (toPercent - fromPercent) * progress, ec);
> +        } else {

Early return here, instead of adding an else branch.
if (ec)
    return SVGLength();
return length;
}
should be sufficient.

> Source/WebCore/svg/SVGLength.h:150
> +                    length.newValueSpecifiedUnits(toType, fromValue + (toValue - fromValue) * progress, ec);
> +            } else {

Same here, early-exit instead of branching.

> Source/WebCore/svg/SVGLength.h:159
> +                if (!ec) {
> +                    float fromValue = convertValueFromUserUnits(fromValueInUserUnits, toType, 0, ec);
> +                    if (!ec) {
> +                        float toValue = valueInSpecifiedUnits();
> +                        length.newValueSpecifiedUnits(toType, fromValue + (toValue - fromValue) * progress, ec);
> +                    }

turn each of these branches in early returns if (ec) return SVGLength()...
Comment 28 Dean Jackson 2011-08-24 17:21:24 PDT
Created attachment 105100 [details]
Patch
Comment 29 Dean Jackson 2011-08-24 17:22:04 PDT
(In reply to comment #27)

Thanks Nikolas. All your comments addressed.
Comment 30 Simon Fraser (smfr) 2011-08-25 11:29:31 PDT
Comment on attachment 105100 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=105100&action=review

> LayoutTests/transitions/resources/transition-test-helpers.js:88
> +        if (isCloseEnough(parseInt(computedValue.red.cssText), expectedValue[0], tolerance) &&
> +            isCloseEnough(parseInt(computedValue.green.cssText), expectedValue[1], tolerance) &&
> +            isCloseEnough(parseInt(computedValue.blue.cssText), expectedValue[2], tolerance))

You could put these into a compareRGBColor function.

> LayoutTests/transitions/svg-transitions-expected.txt:12
> +FAIL - "fill" property for "rect7" element at 1s expected: 0,0,127 but saw: #invalid #0000ff

Did you mean to check in a failing result?

> Source/WebCore/page/animation/AnimationBase.cpp:674
> +class PropertyWrapperSVGPaint : public PropertyWrapperBase {

The name is awkward.
Comment 31 Dean Jackson 2011-08-25 11:48:44 PDT
(In reply to comment #30)

> Did you mean to check in a failing result?

Yes. I'll make a comment in the change log.

> 
> > Source/WebCore/page/animation/AnimationBase.cpp:674
> > +class PropertyWrapperSVGPaint : public PropertyWrapperBase {
> 
> The name is awkward.

Yeah, but they all are. PropertyWrapperAcceleratedOpacity, PropertyWrapperAcceleratedTransform, PropertyWrapperMaybeInvalidColor.

Well, nearly all. We're inconsistent: FillLayersPropertyWrapper
Comment 32 Dean Jackson 2011-08-25 12:18:43 PDT
	M	LayoutTests/ChangeLog
	M	LayoutTests/transitions/resources/transition-test-helpers.js
	A	LayoutTests/transitions/svg-transitions-expected.txt
	A	LayoutTests/transitions/svg-transitions.html
	M	Source/WebCore/ChangeLog
	M	Source/WebCore/page/animation/AnimationBase.cpp
	M	Source/WebCore/rendering/style/RenderStyle.h
	M	Source/WebCore/rendering/style/SVGRenderStyle.h
	M	Source/WebCore/svg/SVGLength.cpp
	M	Source/WebCore/svg/SVGLength.h
Committed r93807

http://trac.webkit.org/changeset/93807