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 28fc84e

Browse files
committedMar 17, 2025·
Revamp fn start_transition_if_applicable to optimize performance
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
1 parent 3e71275 commit 28fc84e

File tree

1 file changed

+85
-117
lines changed

1 file changed

+85
-117
lines changed
 

‎style/animation.rs

+85-117
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);
@@ -1024,48 +1000,7 @@ impl ElementAnimationSet {
10241000
self.dirty = true;
10251001
continue;
10261002
}
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`
1068-
}
1003+
// Step 4 done in `fn start_tranition_if_applicable`
10691004
}
10701005
}
10711006

@@ -1079,85 +1014,118 @@ impl ElementAnimationSet {
10791014
) {
10801015
let style = new_style.get_ui();
10811016
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-
}
1017+
let not_transitionable = !property_declaration_id.is_animatable() ||
1018+
(!allow_discrete && property_declaration_id.is_discrete_animatable());
1019+
1020+
let mut start_new_transition = !not_transitionable;
10881021

10891022
let timing_function = style.transition_timing_function_mod(index);
10901023
let duration = style.transition_duration_mod(index).seconds() as f64;
10911024
let delay = style.transition_delay_mod(index).seconds() as f64;
10921025
let now = context.current_time_for_animations;
10931026

10941027
if duration + delay <= 0.0 {
1095-
return;
1028+
start_new_transition = false;
10961029
}
10971030

1031+
// FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
1032+
let property_declaration = property_declaration_id.to_physical(new_style.writing_mode);
1033+
let from = match AnimationValue::from_computed_values(property_declaration, old_style){
1034+
Some(from) => from,
1035+
None => return
1036+
};
1037+
let to = match AnimationValue::from_computed_values(property_declaration, new_style){
1038+
Some(to)=> to,
1039+
None => return
1040+
};
1041+
10981042
// Only start a new transition if the style actually changes between
10991043
// 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-
};
1044+
if from == to {
1045+
start_new_transition = false;
1046+
}
11101047

11111048
// A property may have an animation type different than 'discrete', but still
11121049
// not be able to interpolate some values. In that case we would fall back to
11131050
// discrete interpolation, so we need to abort if `transition-behavior` doesn't
11141051
// allow discrete transitions.
1115-
if !allow_discrete && !property_animation.from.interpolable_with(&property_animation.to) {
1116-
return;
1052+
if !allow_discrete && !from.interpolable_with(&to) {
1053+
start_new_transition = false;
11171054
}
11181055

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
1056+
// Step 4 in https://drafts.csswg.org/css-transitions/#starting
1057+
// "If the element has a running transition for the property, there is a matching transition-property value,
1058+
let mut running_transition = None;
1059+
if let Some(old_transition) = self
11241060
.transitions
1125-
.iter()
1126-
.filter(|transition| transition.state != AnimationState::Canceled)
1127-
.any(|transition| transition.property_animation.to == property_animation.to)
1061+
.iter_mut()
1062+
.filter(|transition| transition.state != AnimationState::Canceled
1063+
&& transition.state != AnimationState::Finished)
1064+
.find(|transition| {
1065+
transition.property_animation.property_id() == *property_declaration_id
1066+
})
11281067
{
1129-
return;
1068+
// and the end value of the running transition is not equal to the value of the property in the after-change style, then:"
1069+
if to != old_transition.property_animation.to {
1070+
let current_val = old_transition.calculate_value(now);
1071+
let not_transitionable = not_transitionable||
1072+
(!allow_discrete && !current_val.interpolable_with(&to));
1073+
1074+
// Step 4.1
1075+
//"If the current value of the property in the running transition is equal
1076+
// to the value of the property in the after-change style,
1077+
// or if these two values are not transitionable, then implementations must cancel the running transition."
1078+
if current_val == to || not_transitionable {
1079+
old_transition.state = AnimationState::Canceled;
1080+
self.dirty = true;
1081+
start_new_transition = false;
1082+
}
1083+
// Step 4.2
1084+
// "Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the
1085+
// running transition is not transitionable with the value of the property in the after-change style,
1086+
// then implementations must cancel the running transition."
1087+
else if duration + delay <= 0.0 {
1088+
old_transition.state = AnimationState::Canceled;
1089+
self.dirty = true;
1090+
start_new_transition = false;
1091+
}
1092+
} else{
1093+
start_new_transition = false;
1094+
}
1095+
running_transition = Some(old_transition);
11301096
}
11311097

11321098
// Step 1 + 4.3 + 4.4 in https://drafts.csswg.org/css-transitions/#starting
11331099
// We are going to start a new transition, but we might have to update
11341100
// 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-
};
1101+
if start_new_transition {
1102+
let property_animation = PropertyAnimation {
1103+
from,
1104+
to,
1105+
timing_function,
1106+
duration,
1107+
};
1108+
1109+
let reversing_adjusted_start_value = property_animation.from.clone();
1110+
let mut new_transition = Transition {
1111+
start_time: now + delay,
1112+
delay,
1113+
property_animation,
1114+
state: AnimationState::Pending,
1115+
is_new: true,
1116+
reversing_adjusted_start_value,
1117+
reversing_shortening_factor: 1.0,
1118+
};
11451119

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-
{
11541120
// 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-
}
1121+
if let Some(old_transition) = running_transition {
1122+
old_transition.state = AnimationState::Canceled;
1123+
new_transition.update_for_possibly_reversed_transition(old_transition, delay, now);
1124+
}
11581125

1159-
self.transitions.push(new_transition);
1160-
self.dirty = true;
1126+
self.transitions.push(new_transition);
1127+
self.dirty = true;
1128+
}
11611129
}
11621130

11631131
/// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s

0 commit comments

Comments
 (0)
Please sign in to comment.