@@ -1018,127 +1018,133 @@ impl ElementAnimationSet {
10181018 ) {
10191019 let style = new_style. get_ui ( ) ;
10201020 let allow_discrete = style. transition_behavior_mod ( index) == TransitionBehavior :: AllowDiscrete ;
1021- let not_transitionable = !property_declaration_id. is_animatable ( )
1022- || ( !allow_discrete && property_declaration_id. is_discrete_animatable ( ) ) ;
1023-
1024- let mut start_new_transition = !not_transitionable;
1025-
1026- let timing_function = style. transition_timing_function_mod ( index) ;
1027- let duration = style. transition_duration_mod ( index) . seconds ( ) as f64 ;
1028- let delay = style. transition_delay_mod ( index) . seconds ( ) as f64 ;
1029- let now = context. current_time_for_animations ;
1030-
1031- if duration + delay <= 0.0 {
1032- start_new_transition = false ;
1033- }
1034-
10351021 // FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
10361022 let Some ( from) = AnimationValue :: from_computed_values ( property_declaration_id, old_style) else {
10371023 return ;
10381024 } ;
10391025 let Some ( to) = AnimationValue :: from_computed_values ( property_declaration_id, new_style) else {
10401026 return ;
10411027 } ;
1028+ let timing_function = style. transition_timing_function_mod ( index) ;
1029+ let duration = style. transition_duration_mod ( index) . seconds ( ) as f64 ;
1030+ let delay = style. transition_delay_mod ( index) . seconds ( ) as f64 ;
1031+ let now = context. current_time_for_animations ;
1032+ let transitionable = property_declaration_id. is_animatable ( )
1033+ && ( allow_discrete || !property_declaration_id. is_discrete_animatable ( ) ) ;
1034+ let mut has_running_transition = false ;
1035+ let mut has_completed_transition = false ;
10421036
1043- // Only start a new transition if the style actually changes between
1044- // the old style and the new style.
1045- if from == to {
1046- start_new_transition = false ;
1047- }
1048-
1049- // A property may have an animation type different than 'discrete', but still
1050- // not be able to interpolate some values. In that case we would fall back to
1051- // discrete interpolation, so we need to abort if `transition-behavior` doesn't
1052- // allow discrete transitions.
1053- if !allow_discrete && !from. interpolable_with ( & to) {
1054- start_new_transition = false ;
1055- }
1056-
1057- // Step 4 in https://drafts.csswg.org/css-transitions/#starting
1058- // "If the element has a running transition for the property, there is a matching
1059- // transition-property value, and the end value of the running transition is not equal
1060- // to the value of the property in the after-change style, then:"
1061- let mut running_transition = None ;
1062- if let Some ( old_transition) = self
1037+ let mut old_transition= None ;
1038+ if let Some ( uncanceled_transition) = self
10631039 . transitions
10641040 . iter_mut ( )
10651041 . filter ( |transition| transition. state != AnimationState :: Canceled )
10661042 . find ( |transition| {
10671043 transition. property_animation . property_id ( ) == property_declaration_id
10681044 } )
10691045 {
1070- if to != old_transition. property_animation . to {
1071- if old_transition. state != AnimationState :: Finished {
1072- let current_val = old_transition. calculate_value ( now) ;
1073- let not_transitionable = not_transitionable||
1074- ( !allow_discrete && !current_val. interpolable_with ( & to) ) ;
1075-
1076- // Step 4.1
1077- // > If the current value of the property in the running transition
1078- // > is equal to the value of theproperty in the after-change style,
1079- // > or if these two values are not transitionable, then
1080- // > implementations must cancel the running transition.
1081- if current_val == to || not_transitionable {
1082- old_transition. state = AnimationState :: Canceled ;
1083- self . dirty = true ;
1084- return ;
1085- }
1086- // Step 4.2
1087- // "Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the
1088- // running transition is not transitionable with the value of the property in the after-change style,
1089- // then implementations must cancel the running transition."
1090- else if duration + delay <= 0.0 {
1091- old_transition. state = AnimationState :: Canceled ;
1092- self . dirty = true ;
1093- return ;
1094- }
1095- running_transition = Some ( old_transition) ;
1096- }
1097- }
1098- // Per [1], don't trigger a new transition if the end state for that
1099- // transition is the same as that of a transition that's running or
1100- // completed. We don't take into account any canceled animations.
1101- // [1]: https://drafts.csswg.org/css-transitions/#starting
1102- else {
1103- return ;
1104- }
1105- }
1106-
1107- // Step 1 + 4.3 + 4.4 in https://drafts.csswg.org/css-transitions/#starting
1108- // We are going to start a new transition, but we might have to update
1109- // it if we are replacing a reversed transition for step 4.3.
1110- if start_new_transition {
1111- let property_animation = PropertyAnimation {
1112- from,
1113- to,
1114- timing_function,
1115- duration,
1116- } ;
1117-
1118- let reversing_adjusted_start_value = property_animation. from . clone ( ) ;
1119- let mut new_transition = Transition {
1120- start_time : now + delay,
1121- delay,
1122- property_animation,
1123- state : AnimationState :: Pending ,
1124- is_new : true ,
1125- reversing_adjusted_start_value,
1126- reversing_shortening_factor : 1.0 ,
1046+ match uncanceled_transition. state {
1047+ AnimationState :: Finished => has_completed_transition = true ,
1048+ _ => has_running_transition = true ,
11271049 } ;
1050+ old_transition = Some ( uncanceled_transition) ;
1051+ }
11281052
1129- // We always cancel any running transitions for the same property, according to step 4.
1130- if let Some ( old_transition) = running_transition {
1131- old_transition. state = AnimationState :: Canceled ;
1132- new_transition. update_for_possibly_reversed_transition ( old_transition, delay, now) ;
1053+ // Step 1 in https://drafts.csswg.org/css-transitions/#starting
1054+ // > If all of the following are true:
1055+ // > 1. the element does not have a running transition for the property,
1056+ // > 2. the before-change style is different from the after-change style for that property,
1057+ // > and the values for the property are transitionable,
1058+ // > 4. there is a matching transition-property value, and
1059+ // > 5. the combined duration is greater than 0s,
1060+ if !has_running_transition && ( transitionable && from != to) && ( duration + delay > 0.0 ) {
1061+ // > 3. the element does not have a completed transition for the property or the end value
1062+ // > of the completed transition is different from the after-change style for the property
1063+ let mut start_new_transition = !has_completed_transition;
1064+ if has_completed_transition {
1065+ let completed_transition = old_transition. as_ref ( ) . unwrap ( ) ;
1066+ start_new_transition = completed_transition. property_animation . to != to;
11331067 }
1068+ // > then implementations must remove the completed transition (if present) from
1069+ // > the set of completed transitions and start a transition...
1070+ if start_new_transition {
1071+ let property_animation = PropertyAnimation {
1072+ from : from. clone ( ) ,
1073+ to,
1074+ timing_function,
1075+ duration,
1076+ } ;
1077+ let new_transition = Transition {
1078+ start_time : now + delay,
1079+ delay,
1080+ property_animation,
1081+ state : AnimationState :: Pending ,
1082+ is_new : true ,
1083+ reversing_adjusted_start_value : from. clone ( ) ,
1084+ reversing_shortening_factor : 1.0 ,
1085+ } ;
1086+ self . transitions . push ( new_transition) ;
1087+ self . dirty = true ;
1088+ return ;
1089+ }
1090+ }
1091+ // Step 2 will be done later in `fn process_animations_for_style`
1092+ // Step 3 will be done later in `fn update_transitions_for_new_style`
11341093
1135- self . transitions . push ( new_transition) ;
1136- self . dirty = true ;
1094+ // Step 4 in https://drafts.csswg.org/css-transitions/#starting
1095+ // "If the element has a running transition for the property, there is a matching
1096+ // transition-property value, and the end value of the running transition is not equal
1097+ // to the value of the property in the after-change style, then:"
1098+ if has_running_transition {
1099+ let running_transition = old_transition. unwrap ( ) ;
1100+ if running_transition. property_animation . to != to {
1101+ let current_val = running_transition. calculate_value ( now) ;
1102+ let transitionable =
1103+ transitionable && ( allow_discrete || current_val. interpolable_with ( & to) ) ;
1104+ // Step 4.1
1105+ // > If the current value of the property in the running transition
1106+ // > is equal to the value of theproperty in the after-change style,
1107+ // > or if these two values are not transitionable, then
1108+ // > implementations must cancel the running transition.
1109+ if current_val == to || !transitionable {
1110+ running_transition. state = AnimationState :: Canceled ;
1111+ self . dirty = true ;
1112+ }
1113+ // Step 4.2
1114+ // "Otherwise, if the combined duration is less than or equal to 0s,
1115+ // or if the current value of the property in the running transition is not
1116+ // transitionable with the value of the property in the after-change style,
1117+ // then implementations must cancel the running transition."
1118+ else if duration + delay <= 0.0 {
1119+ running_transition. state = AnimationState :: Canceled ;
1120+ self . dirty = true ;
1121+ }
1122+ //step 4.3 + 4.4. Cancel running transition and start a new one.
1123+ else {
1124+ running_transition. state = AnimationState :: Canceled ;
1125+ let property_animation = PropertyAnimation {
1126+ from : from. clone ( ) ,
1127+ to,
1128+ timing_function,
1129+ duration,
1130+ } ;
1131+ let mut new_transition = Transition {
1132+ start_time : now + delay,
1133+ delay,
1134+ property_animation,
1135+ state : AnimationState :: Pending ,
1136+ is_new : true ,
1137+ reversing_adjusted_start_value : from. clone ( ) ,
1138+ reversing_shortening_factor : 1.0 ,
1139+ } ;
1140+ new_transition. update_for_possibly_reversed_transition ( running_transition, delay, now) ;
1141+ self . transitions . push ( new_transition) ;
1142+ self . dirty = true ;
1143+ }
1144+ }
11371145 }
11381146 }
11391147
1140-
1141-
11421148 /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
11431149 /// transitions that depends on flag.
11441150 fn get_value_map_for_transitions ( & self , now : f64 , flag : IncludedTransitions ) -> Option < AnimationValueMap > {
0 commit comments