On Wed, 29 Jan 2020 20:47:11 GMT, Kevin Rushforth <k...@openjdk.org> wrote:

>> [8236858](https://bugs.openjdk.java.net/browse/JDK-8236858) (Animations do 
>> not play backwards after being paused) has been split to deal with 
>> [embedded](https://bugs.openjdk.java.net/browse/JDK-8237974) and [not 
>> embedded](https://bugs.openjdk.java.net/browse/JDK-8237975) animations. This 
>> is a fix for the latter.
>> The reason for the split is that embedded animations have a much more 
>> complex behavior. The current state of the relation between an animation and 
>> its clip envelope is already messy and should be corrected, even more so for 
>> embedded animations whose parent controls their behavior as well (sometimes 
>> in conflict with the child's clip envelope). This will require a redesign 
>> which can be discussed for 15. See the parent issue 
>> [8210238](https://bugs.openjdk.java.net/browse/JDK-8210238) for the list of 
>> bugs that arise from it.
>> 
>> This simple fix allows to change the current rate of a `ClipEnvelope` also 
>> when the animations is `PAUSED`. A possible issue with this approach is that 
>> it changes the buggy behavior of embedded animations to a different buggy 
>> behavior.
>> 
>> A concept test has been added, but it does not work yet since the mock clip 
>> envelope does not have sufficient behavior (`doTimePulse` does not actually 
>> do a time pulse). Open for ideas on how to make it simple, otherwise I will 
>> add a method to set a clip envelope and create a new one ad-hoc.
> 
> modules/javafx.graphics/src/main/java/com/sun/scenario/animation/shared/FiniteClipEnvelope.java
>  line 85:
> 
>> 84:         if (status != Status.STOPPED) {
>> 85:             setInternalCurrentRate((Math.abs(currentRate - this.rate) < 
>> EPSILON) ? rate : -rate);
>> 86:             deltaTicks = newTicks - Math.round((ticks - deltaTicks) * 
>> Math.abs(rate / this.rate));
> 
> What are the implications of not calling the existing `setCurrentRate` method 
> for animations that are in the `RUNNING` state? It means that 
> `Animation::setCurrentRate` will no longer be called in that case. Should it 
> be?
> 
> Independent of your change, I can't figure out why the existing logic works 
> today, even for animations that are running. The expression 
> `(Math.abs(currentRate - this.rate) < EPSILON) ? rate : -rate` will evaluate 
> either to `rate` or `-rate` depending on whether `currentRate` and 
> `this.rate` are closer to each other than epsilon, irrespective of whether 
> either (or both) of `this.rate` or `currentRate` are positive or negative. I 
> feel I must be missing something.

> What are the implications of not calling the existing `setCurrentRate` method 
> for animations that are in the `RUNNING` state? It means that 
> `Animation::setCurrentRate` will no longer be called in that case. Should it 
> be?

The situation is complicated (to put it politely), as you've realized. 
`currentRate` is actually being set from `Animation#setRate` first, then 
`ClipEnvelope.setRate` sets it again. I initially removed `currentRate` from 
`ClipEnvelope` altogether, but that broke embedded animations whose rate is 
being set by their parent through their `ClipEnvelope` (doing it through 
`Animation` will throw an exception). So, instead, I added a "backdoor" for the 
parent to change its child's `ClipEnvelope.currentRate` without changing its 
`Animation.currentRate`.

The result is that non-embedded animations now work correctly and embedded 
animations are still broken, but in a slightly different way. Their 
`Animation.currentRate` is now always 1 instead of either 1 or -1, but this is 
incorrect anyway if the rate is not 1 or -1.

> Independent of your change, I can't figure out why the existing logic works 
> today, even for animations that are running. The expression 
> `(Math.abs(currentRate - this.rate) < EPSILON) ? rate : -rate` will evaluate 
> either to `rate` or `-rate` depending on whether `currentRate` and 
> `this.rate` are closer to each other than epsilon, irrespective of whether 
> either (or both) of `this.rate` or `currentRate` are positive or negative. I 
> feel I must be missing something.

There's a lot I couldn't figure out in time for 14, especially with regard to 
embedded animations (have a look at `ParallelTransition.doPlayTo`).

For non-embedded animations, If the animation is `RUNNING`, then:
* If the animation is during a forward cycle then `currentRate == this.rate`, 
so the current rate is set to the new rate.
* If the animation is during a reverse cycle, then `currentRate == -this.rate`, 
so the current rate is set to the negative of the new rate (to accommodate the 
reverse cycle's rule of `currentRate == -rate`).

However, this check is already done in `Animation.rate`'s `invalidate` method, 
where the cryptic `Math.abs(currentRate - this.rate) < EPSILON` is at least 
given the name `playingForward`:
if (getStatus() == Status.RUNNING) {                                            
 
    final double currentRate = getCurrentRate();                                
 
    if (Math.abs(currentRate) < EPSILON) {                                      
 
        doSetCurrentRate(lastPlayedForward ? newRate : -newRate);               
 
        resumeReceiver();                                                       
 
    } else {                                                                    
 
        final boolean playingForward = Math.abs(currentRate - oldRate) < 
EPSILON; // HERE
        doSetCurrentRate(playingForward ? newRate : -newRate);  // AND HERE
    }                                                                           
 
}                                                                               
 
oldRate = newRate;                                                              
 

For embedded animations this is even worse, since there is an additional rate 
property kept in the parent animations (`rates[i]`), so the rate is kept in 3 
places...

Overall, the animation area will require a soft redesign. That might weed out 
the bugs in bulk. The more I was working to find a fix the more bugs I found. I 
turned [JDK-8210238](https://bugs.openjdk.java.net/browse/JDK-8210238) to an 
umbrella issue to keep track.

-------------

PR: https://git.openjdk.java.net/jfx/pull/98

Reply via email to