@@ -70,7 +70,7 @@ impl PropertyAnimation {
70
70
let to = AnimationValue :: from_computed_values ( property_declaration, new_style) ?;
71
71
let duration = duration. seconds ( ) as f64 ;
72
72
73
- if from == to || duration = = 0.0 {
73
+ if from == to || duration < = 0.0 {
74
74
return None ;
75
75
}
76
76
@@ -1015,11 +1015,59 @@ impl ElementAnimationSet {
1015
1015
if transition. state == AnimationState :: Finished {
1016
1016
continue ;
1017
1017
}
1018
- if transitioning_properties. contains ( transition. property_animation . property_id ( ) ) {
1018
+ // Step 3 in https://drafts.csswg.org/css-transitions/#starting
1019
+ // "If the element has a running transition or completed transition for the property,
1020
+ // and there is not a matching transition-property value, then implementations
1021
+ // must cancel the running transition or remove the completed transition from the set of completed transitions."
1022
+ let transition_property_id = transition. property_animation . property_id ( ) ;
1023
+ if !transitioning_properties. contains ( transition_property_id) {
1024
+ transition. state = AnimationState :: Canceled ;
1025
+ self . dirty = true ;
1019
1026
continue ;
1020
1027
}
1021
- transition. state = AnimationState :: Canceled ;
1022
- self . dirty = true ;
1028
+
1029
+
1030
+ // Never panic: We made sure in fn start_transition_if_applicable if a transition is valid, after_change_to is also valid
1031
+ let after_change_to = AnimationValue :: from_computed_values ( transition_property_id, & after_change_style) . unwrap ( ) ;
1032
+ // Step 4
1033
+ // "If the element has a running transition for the property, there is a matching transition-property value,
1034
+ // and the end value of the running transition is not equal to the value of the property in the after-change style, then:"
1035
+ if transition. property_animation . to != after_change_to {
1036
+ // index for after-change transition declaration
1037
+ let index = after_change_style. transition_properties ( ) . position ( |declared_transition| declared_transition. property
1038
+ . as_borrowed ( )
1039
+ . to_physical ( after_change_style. writing_mode ) == transition_property_id) . unwrap ( ) ;
1040
+
1041
+ let now = context. current_time_for_animations ;
1042
+ let after_change_style = after_change_style. get_ui ( ) ;
1043
+ let allow_discrete = after_change_style. transition_behavior_mod ( index) == TransitionBehavior :: AllowDiscrete ;
1044
+ let current_val = transition. calculate_value ( now) ;
1045
+ let not_transitionable =
1046
+ ( !transition_property_id. is_animatable ( ) || ( !allow_discrete && transition_property_id. is_discrete_animatable ( ) ) )
1047
+ || ( !current_val. interpolable_with ( & after_change_to) ) ;
1048
+ let combined_duration = after_change_style. transition_duration_mod ( index) . seconds ( ) + after_change_style. transition_delay_mod ( index) . seconds ( ) ;
1049
+ // Step 4.1
1050
+ //"If the current value of the property in the running transition is equal
1051
+ // to the value of the property in the after-change style,
1052
+ // or if these two values are not transitionable, then implementations must cancel the running transition."
1053
+
1054
+ if current_val == after_change_to || not_transitionable {
1055
+ transition. state = AnimationState :: Canceled ;
1056
+ self . dirty = true ;
1057
+ continue ;
1058
+ }
1059
+ // Step 4.2
1060
+ // "Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the
1061
+ // running transition is not transitionable with the value of the property in the after-change style,
1062
+ // then implementations must cancel the running transition."
1063
+ else if combined_duration <= 0.0 {
1064
+ transition. state = AnimationState :: Canceled ;
1065
+ self . dirty = true ;
1066
+ continue ;
1067
+ }
1068
+
1069
+ //Step 4.4
1070
+ }
1023
1071
}
1024
1072
}
1025
1073
@@ -1079,6 +1127,7 @@ impl ElementAnimationSet {
1079
1127
return ;
1080
1128
}
1081
1129
1130
+ // Step 1 in https://drafts.csswg.org/css-transitions/#starting
1082
1131
// We are going to start a new transition, but we might have to update
1083
1132
// it if we are replacing a reversed transition.
1084
1133
let reversing_adjusted_start_value = property_animation. from . clone ( ) ;
@@ -1129,6 +1178,26 @@ impl ElementAnimationSet {
1129
1178
Some ( map)
1130
1179
}
1131
1180
1181
+ /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
1182
+ /// transitions that are not canceled or finished at the given time value.
1183
+ pub fn get_value_map_for_running_transitions ( & self , now : f64 ) -> Option < AnimationValueMap > {
1184
+ if !self . has_active_transition ( ) {
1185
+ return None ;
1186
+ }
1187
+
1188
+ let mut map =
1189
+ AnimationValueMap :: with_capacity_and_hasher ( self . transitions . len ( ) , Default :: default ( ) ) ;
1190
+ for transition in & self . transitions {
1191
+ if transition. state == AnimationState :: Canceled || transition. state == AnimationState :: Finished {
1192
+ continue ;
1193
+ }
1194
+ let value = transition. calculate_value ( now) ;
1195
+ map. insert ( value. id ( ) . to_owned ( ) , value) ;
1196
+ }
1197
+
1198
+ Some ( map)
1199
+ }
1200
+
1132
1201
/// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
1133
1202
/// active animations at the given time value.
1134
1203
pub fn get_value_map_for_active_animations ( & self , now : f64 ) -> Option < AnimationValueMap > {
@@ -1235,7 +1304,7 @@ impl DocumentAnimationSet {
1235
1304
self . sets
1236
1305
. read ( )
1237
1306
. get ( key)
1238
- . and_then ( |set| set. get_value_map_for_active_transitions ( time) )
1307
+ . and_then ( |set| set. get_value_map_for_running_transitions ( time) )
1239
1308
. map ( |map| {
1240
1309
let block = PropertyDeclarationBlock :: from_animation_value_map ( & map) ;
1241
1310
Arc :: new ( shared_lock. wrap ( block) )
0 commit comments