-
Notifications
You must be signed in to change notification settings - Fork 24
The simple iteration progress shouldn't stick to the last iteration just because we're in the after phase #201
Description
Background: Mozilla bug 1406381
The procedure to calculate the simple iteration progress includes the following steps:
- If all of the following conditions are true,
- the simple iteration progress calculated above is zero,
- the animation effect is in the after phase, and
- iteration count is not equal to zero, and
- either the active time is not zero or the iteration duration is zero.
let the simple iteration progress be 1.0.
The idea here is that when we happen to end at the end of an iteration instead of sticking to the beginning of the next iteration we stick to the end of the last iteration. This is normally what you want and basically every animation system does this (SMIL dictates this but unfortunately CSS animations just doesn't define these sort of details).
There are two issues here, however:
- Relying on the animation phase means this doesn't work for the case where the playback rate is negative and we are precisely at the end of the animation since in that case the phase will be active. (This is the issue observed in the linked-to Mozilla bug.)
- This definition is slightly surprising when combined with a negative end delay. Normally when you have a negative end delay it clips the playback interval but you can still seek into the clipped interval. With the above definition if you seek to the end of any iteration in the clipped range it will stick to the end of the iteration instead of the start. This is different to the behavior when seeking in the non-clipped range.
Fixing the first issue is not too bad (although a lot harder than I first anticipated due to zero-duration interations).
One possible approach is to check for the "after" phase OR the "active" phase and a local time equal to the active-after boundary. Or at least I think that worked, from memory. The key point is to check the phase since otherwise animations with zero-duration iterations start applying this behavior in the before phase and everything falls apart. It's a little odd, however, to include the local time and active-after boundary in this definition. It seems like a bit of a layering violation given the way these definitions continually refine the output time in terms of the previous step's output.
Another alternative is to define active end time as max(min(active duration, active duration + end delay), 0) and then check for "after" phase OR the "active" phase AND also an active time ≥ active end time.
However, that doesn't fix the second issue. If we agree that needs fixing then I think the solution would be to just check for "after" phase OR the "active" phase AND and active time = active duration. That would mean that if you use the end delay to shorten an animation such that the animation interval is clipped and finishes exactly at the end of an iteration (but not the last iteration) it would fill forwards with the start of the next interval. You'd only get the "stick to the last interval" behavior if you actually played to the end of the active interval.
I suspect there's no significant compatibility issue here since I don't think end delays are used a lot, and when they are, they're not used to clip to a whole iteration amount, but I'd be interested if anyone else has comments about this.