Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0cf369f

Browse files
committedMar 18, 2025·
Revamp fn start_transition_if_applicable to optimize performance
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
1 parent 5aae785 commit 0cf369f

File tree

1 file changed

+85
-119
lines changed

1 file changed

+85
-119
lines changed
 

‎style/animation.rs

+85-119
Original file line numberDiff line numberDiff line change
@@ -57,30 +57,6 @@ impl PropertyAnimation {
5757
self.from.id()
5858
}
5959

60-
fn from_property_declaration(
61-
property_declaration: &PropertyDeclarationId,
62-
timing_function: TimingFunction,
63-
duration: f64,
64-
old_style: &ComputedValues,
65-
new_style: &ComputedValues,
66-
) -> Option<PropertyAnimation> {
67-
// FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
68-
let property_declaration = property_declaration.to_physical(new_style.writing_mode);
69-
let from = AnimationValue::from_computed_values(property_declaration, old_style)?;
70-
let to = AnimationValue::from_computed_values(property_declaration, new_style)?;
71-
72-
if from == to {
73-
return None;
74-
}
75-
76-
Some(PropertyAnimation {
77-
from,
78-
to,
79-
timing_function,
80-
duration,
81-
})
82-
}
83-
8460
/// The output of the timing function given the progress ration of this animation.
8561
fn timing_function_output(&self, progress: f64) -> f64 {
8662
let epsilon = 1. / (200. * self.duration);
@@ -1022,142 +998,132 @@ impl ElementAnimationSet {
1022998
if !transitioning_properties.contains(transition_property_id) {
1023999
transition.state = AnimationState::Canceled;
10241000
self.dirty = true;
1025-
continue;
1026-
}
1027-
1028-
let after_change_to = AnimationValue::from_computed_values(transition_property_id, &after_change_style).unwrap();
1029-
// Step 4
1030-
// "If the element has a running transition for the property, there is a matching transition-property value,
1031-
// and the end value of the running transition is not equal to the value of the property in the after-change style, then:"
1032-
if transition.property_animation.to != after_change_to {
1033-
// index for after-change transition declaration
1034-
let index = after_change_style.transition_properties().position(|declared_transition| declared_transition.property
1035-
.as_borrowed()
1036-
.to_physical(after_change_style.writing_mode) == transition_property_id).unwrap();
1037-
1038-
let now = context.current_time_for_animations;
1039-
let after_change_style = after_change_style.get_ui();
1040-
let allow_discrete = after_change_style.transition_behavior_mod(index) == TransitionBehavior::AllowDiscrete;
1041-
let current_val = transition.calculate_value(now);
1042-
let not_transitionable =
1043-
(!transition_property_id.is_animatable() || (!allow_discrete && transition_property_id.is_discrete_animatable()))
1044-
|| (!allow_discrete && !current_val.interpolable_with(&after_change_to));
1045-
1046-
let combined_duration = after_change_style.transition_duration_mod(index).seconds() + after_change_style.transition_delay_mod(index).seconds();
1047-
1048-
// Step 4.1
1049-
//"If the current value of the property in the running transition is equal
1050-
// to the value of the property in the after-change style,
1051-
// or if these two values are not transitionable, then implementations must cancel the running transition."
1052-
if current_val == after_change_to || not_transitionable {
1053-
transition.state = AnimationState::Canceled;
1054-
self.dirty = true;
1055-
continue;
1056-
}
1057-
// Step 4.2
1058-
// "Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the
1059-
// running transition is not transitionable with the value of the property in the after-change style,
1060-
// then implementations must cancel the running transition."
1061-
else if combined_duration <= 0.0 {
1062-
transition.state = AnimationState::Canceled;
1063-
self.dirty = true;
1064-
continue;
1065-
}
1066-
1067-
//Step 4.3, 4.4 have been done in `fn start_transition_if_applicable`
10681001
}
1002+
// Step 4 was done in `fn start_transition_if_applicable`
10691003
}
10701004
}
10711005

10721006
fn start_transition_if_applicable(
10731007
&mut self,
10741008
context: &SharedStyleContext,
1075-
property_declaration_id: &PropertyDeclarationId,
1009+
property_declaration: PropertyDeclarationId,
10761010
index: usize,
10771011
old_style: &ComputedValues,
10781012
new_style: &Arc<ComputedValues>,
10791013
) {
10801014
let style = new_style.get_ui();
10811015
let allow_discrete = style.transition_behavior_mod(index) == TransitionBehavior::AllowDiscrete;
1082-
1083-
if !property_declaration_id.is_animatable()
1084-
|| (!allow_discrete && property_declaration_id.is_discrete_animatable())
1085-
{
1086-
return;
1087-
}
1016+
let not_transitionable = !property_declaration.is_animatable() ||
1017+
(!allow_discrete && property_declaration.is_discrete_animatable());
1018+
1019+
let mut start_new_transition = !not_transitionable;
10881020

10891021
let timing_function = style.transition_timing_function_mod(index);
10901022
let duration = style.transition_duration_mod(index).seconds() as f64;
10911023
let delay = style.transition_delay_mod(index).seconds() as f64;
10921024
let now = context.current_time_for_animations;
10931025

10941026
if duration + delay <= 0.0 {
1095-
return;
1027+
start_new_transition = false;
10961028
}
10971029

1030+
// FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
1031+
let Some(from) = AnimationValue::from_computed_values(property_declaration, old_style) else {
1032+
return;
1033+
};
1034+
let Some(to) = AnimationValue::from_computed_values(property_declaration, new_style) else {
1035+
return;
1036+
};
1037+
1038+
10981039
// Only start a new transition if the style actually changes between
10991040
// the old style and the new style.
1100-
let property_animation = match PropertyAnimation::from_property_declaration(
1101-
property_declaration_id,
1102-
timing_function,
1103-
duration,
1104-
old_style,
1105-
new_style,
1106-
) {
1107-
Some(property_animation) => property_animation,
1108-
None => return,
1109-
};
1041+
if from == to {
1042+
start_new_transition = false;
1043+
}
11101044

11111045
// A property may have an animation type different than 'discrete', but still
11121046
// not be able to interpolate some values. In that case we would fall back to
11131047
// discrete interpolation, so we need to abort if `transition-behavior` doesn't
11141048
// allow discrete transitions.
1115-
if !allow_discrete && !property_animation.from.interpolable_with(&property_animation.to) {
1116-
return;
1049+
if !allow_discrete && !from.interpolable_with(&to) {
1050+
start_new_transition = false;
11171051
}
11181052

1119-
// Per [1], don't trigger a new transition if the end state for that
1120-
// transition is the same as that of a transition that's running or
1121-
// completed. We don't take into account any canceled animations.
1122-
// [1]: https://drafts.csswg.org/css-transitions/#starting
1123-
if self
1053+
// Step 4 in https://drafts.csswg.org/css-transitions/#starting
1054+
// "If the element has a running transition for the property, there is a matching transition-property value,
1055+
let mut running_transition = None;
1056+
if let Some(old_transition) = self
11241057
.transitions
1125-
.iter()
1058+
.iter_mut()
11261059
.filter(|transition| transition.state != AnimationState::Canceled)
1127-
.any(|transition| transition.property_animation.to == property_animation.to)
1060+
.find(|transition| {
1061+
transition.property_animation.property_id() == property_declaration
1062+
})
11281063
{
1129-
return;
1064+
// and the end value of the running transition is not equal to the value of the property in the after-change style, then:"
1065+
if to != old_transition.property_animation.to {
1066+
let current_val = old_transition.calculate_value(now);
1067+
let not_transitionable = not_transitionable||
1068+
(!allow_discrete && !current_val.interpolable_with(&to));
1069+
1070+
// Step 4.1
1071+
//"If the current value of the property in the running transition is equal
1072+
// to the value of the property in the after-change style,
1073+
// or if these two values are not transitionable, then implementations must cancel the running transition."
1074+
if current_val == to || not_transitionable {
1075+
old_transition.state = AnimationState::Canceled;
1076+
self.dirty = true;
1077+
start_new_transition = false;
1078+
}
1079+
// Step 4.2
1080+
// "Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the
1081+
// running transition is not transitionable with the value of the property in the after-change style,
1082+
// then implementations must cancel the running transition."
1083+
else if duration + delay <= 0.0 {
1084+
old_transition.state = AnimationState::Canceled;
1085+
self.dirty = true;
1086+
start_new_transition = false;
1087+
}
1088+
} else{
1089+
start_new_transition = false;
1090+
}
1091+
running_transition = Some(old_transition);
11301092
}
11311093

11321094
// Step 1 + 4.3 + 4.4 in https://drafts.csswg.org/css-transitions/#starting
11331095
// We are going to start a new transition, but we might have to update
11341096
// it if we are replacing a reversed transition.
1135-
let reversing_adjusted_start_value = property_animation.from.clone();
1136-
let mut new_transition = Transition {
1137-
start_time: now + delay,
1138-
delay,
1139-
property_animation,
1140-
state: AnimationState::Pending,
1141-
is_new: true,
1142-
reversing_adjusted_start_value,
1143-
reversing_shortening_factor: 1.0,
1144-
};
1097+
if start_new_transition {
1098+
let property_animation = PropertyAnimation {
1099+
from,
1100+
to,
1101+
timing_function,
1102+
duration,
1103+
};
1104+
1105+
let reversing_adjusted_start_value = property_animation.from.clone();
1106+
let mut new_transition = Transition {
1107+
start_time: now + delay,
1108+
delay,
1109+
property_animation,
1110+
state: AnimationState::Pending,
1111+
is_new: true,
1112+
reversing_adjusted_start_value,
1113+
reversing_shortening_factor: 1.0,
1114+
};
11451115

1146-
if let Some(old_transition) = self
1147-
.transitions
1148-
.iter_mut()
1149-
.filter(|transition| transition.state == AnimationState::Running)
1150-
.find(|transition| {
1151-
transition.property_animation.property_id() == *property_declaration_id
1152-
})
1153-
{
11541116
// We always cancel any running transitions for the same property.
1155-
old_transition.state = AnimationState::Canceled;
1156-
new_transition.update_for_possibly_reversed_transition(old_transition, delay, now);
1157-
}
1117+
if let Some(old_transition) = running_transition {
1118+
if old_transition.state == AnimationState::Running {
1119+
old_transition.state = AnimationState::Canceled;
1120+
new_transition.update_for_possibly_reversed_transition(old_transition, delay, now);
1121+
}
1122+
}
11581123

1159-
self.transitions.push(new_transition);
1160-
self.dirty = true;
1124+
self.transitions.push(new_transition);
1125+
self.dirty = true;
1126+
}
11611127
}
11621128

11631129
/// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
@@ -1370,7 +1336,7 @@ pub fn start_transitions_if_applicable(
13701336
properties_that_transition.insert(physical_property);
13711337
animation_state.start_transition_if_applicable(
13721338
context,
1373-
&physical_property,
1339+
physical_property,
13741340
transition.index,
13751341
old_style,
13761342
new_style,

0 commit comments

Comments
 (0)
Please sign in to comment.