Skip to content

Commit 4ef8b50

Browse files
committed
Revamp fn start_transition_if_applicable to optimize performance
Signed-off-by: Euclid Ye <[email protected]>
1 parent 5aae785 commit 4ef8b50

File tree

1 file changed

+83
-117
lines changed

1 file changed

+83
-117
lines changed

style/animation.rs

+83-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 was done in `fn start_transition_if_applicable`
10691004
}
10701005
}
10711006

@@ -1079,85 +1014,116 @@ 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 Some(from) = AnimationValue::from_computed_values(property_declaration, old_style) else {
1034+
return;
1035+
};
1036+
let Some(to) = AnimationValue::from_computed_values(property_declaration, new_style) else {
1037+
return;
1038+
};
1039+
10981040
// Only start a new transition if the style actually changes between
10991041
// 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-
};
1042+
if from == to {
1043+
start_new_transition = false;
1044+
}
11101045

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

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

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

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

0 commit comments

Comments
 (0)