зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1646811 - servo: Include animations and transitions in the cascade.
Instead of applying animations and transitions to styled elements, include them in the cascade. This allows them to interact properly with things like font-size and !important rules. Depends on D80234 Differential Revision: https://phabricator.services.mozilla.com/D80235
This commit is contained in:
Родитель
697bb739d1
Коммит
7b23d8c773
|
@ -10,7 +10,7 @@
|
|||
use crate::bezier::Bezier;
|
||||
use crate::context::{CascadeInputs, SharedStyleContext};
|
||||
use crate::dom::{OpaqueNode, TDocument, TElement, TNode};
|
||||
use crate::properties::animated_properties::AnimationValue;
|
||||
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
|
||||
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
|
||||
use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode;
|
||||
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
|
||||
|
@ -127,13 +127,11 @@ impl PropertyAnimation {
|
|||
}
|
||||
|
||||
/// Update the given animation at a given point of progress.
|
||||
fn update(&self, style: &mut ComputedValues, progress: f64) {
|
||||
fn calculate_value(&self, progress: f64) -> Result<AnimationValue, ()> {
|
||||
let procedure = Procedure::Interpolate {
|
||||
progress: self.timing_function_output(progress),
|
||||
};
|
||||
if let Ok(new_value) = self.from.animate(&self.to, procedure) {
|
||||
new_value.set_in_style_for_servo(style);
|
||||
}
|
||||
self.from.animate(&self.to, procedure)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,16 +596,14 @@ impl Animation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Update the given style to reflect the values specified by this `Animation`
|
||||
/// at the time provided by the given `SharedStyleContext`.
|
||||
fn update_style(&self, context: &SharedStyleContext, style: &mut Arc<ComputedValues>) {
|
||||
/// Fill in an `AnimationValueMap` with values calculated from this animation at
|
||||
/// the given time value.
|
||||
fn get_property_declaration_at_time(&self, now: f64, map: &mut AnimationValueMap) {
|
||||
let duration = self.duration;
|
||||
let started_at = self.started_at;
|
||||
|
||||
let now = match self.state {
|
||||
AnimationState::Running | AnimationState::Pending | AnimationState::Finished => {
|
||||
context.current_time_for_animations
|
||||
},
|
||||
AnimationState::Running | AnimationState::Pending | AnimationState::Finished => now,
|
||||
AnimationState::Paused(progress) => started_at + duration * progress,
|
||||
AnimationState::Canceled => return,
|
||||
};
|
||||
|
@ -666,7 +662,7 @@ impl Animation {
|
|||
}
|
||||
|
||||
debug!(
|
||||
"Animation::update_style: keyframe from {:?} to {:?}",
|
||||
"Animation::get_property_declaration_at_time: keyframe from {:?} to {:?}",
|
||||
prev_keyframe_index, next_keyframe_index
|
||||
);
|
||||
|
||||
|
@ -676,20 +672,19 @@ impl Animation {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let update_with_single_keyframe_style = |style, keyframe: &ComputedKeyframe| {
|
||||
let mutable_style = Arc::make_mut(style);
|
||||
let mut add_declarations_to_map = |keyframe: &ComputedKeyframe| {
|
||||
for value in keyframe.values.iter() {
|
||||
value.set_in_style_for_servo(mutable_style);
|
||||
map.insert(value.id(), value.clone());
|
||||
}
|
||||
};
|
||||
|
||||
if total_progress <= 0.0 {
|
||||
update_with_single_keyframe_style(style, &prev_keyframe);
|
||||
add_declarations_to_map(&prev_keyframe);
|
||||
return;
|
||||
}
|
||||
|
||||
if total_progress >= 1.0 {
|
||||
update_with_single_keyframe_style(style, &next_keyframe);
|
||||
add_declarations_to_map(&next_keyframe);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -707,18 +702,18 @@ impl Animation {
|
|||
};
|
||||
|
||||
let relative_progress = (now - last_keyframe_ended_at) / relative_duration;
|
||||
let mut new_style = (**style).clone();
|
||||
for (from, to) in prev_keyframe.values.iter().zip(next_keyframe.values.iter()) {
|
||||
PropertyAnimation {
|
||||
let animation = PropertyAnimation {
|
||||
from: from.clone(),
|
||||
to: to.clone(),
|
||||
timing_function: prev_keyframe.timing_function,
|
||||
duration: relative_duration as f64,
|
||||
}
|
||||
.update(&mut new_style, relative_progress);
|
||||
}
|
||||
};
|
||||
|
||||
*Arc::make_mut(style) = new_style;
|
||||
if let Ok(value) = animation.calculate_value(relative_progress) {
|
||||
map.insert(value.id(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -799,7 +794,10 @@ impl Transition {
|
|||
// time of the style change event, times the reversing shortening
|
||||
// factor of the old transition
|
||||
// 2. 1 minus the reversing shortening factor of the old transition."
|
||||
let transition_progress = replaced_transition.progress(now);
|
||||
let transition_progress = ((now - replaced_transition.start_time) /
|
||||
(replaced_transition.property_animation.duration))
|
||||
.min(1.0)
|
||||
.max(0.0);
|
||||
let timing_function_output = replaced_animation.timing_function_output(transition_progress);
|
||||
let old_reversing_shortening_factor = replaced_transition.reversing_shortening_factor;
|
||||
self.reversing_shortening_factor = ((timing_function_output *
|
||||
|
@ -845,25 +843,16 @@ impl Transition {
|
|||
time >= self.start_time + (self.property_animation.duration)
|
||||
}
|
||||
|
||||
/// Whether this animation has the same end value as another one.
|
||||
#[inline]
|
||||
fn progress(&self, now: f64) -> f64 {
|
||||
let progress = (now - self.start_time) / (self.property_animation.duration);
|
||||
progress.min(1.0)
|
||||
}
|
||||
|
||||
/// Update a style to the value specified by this `Transition` given a `SharedStyleContext`.
|
||||
fn update_style(&self, context: &SharedStyleContext, style: &mut Arc<ComputedValues>) {
|
||||
// Never apply canceled transitions to a style.
|
||||
if self.state == AnimationState::Canceled {
|
||||
return;
|
||||
/// Update the given animation at a given point of progress.
|
||||
pub fn calculate_value(&self, time: f64) -> Option<AnimationValue> {
|
||||
let progress = (time - self.start_time) / (self.property_animation.duration);
|
||||
if progress < 0.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let progress = self.progress(context.current_time_for_animations);
|
||||
if progress >= 0.0 {
|
||||
self.property_animation
|
||||
.update(Arc::make_mut(style), progress);
|
||||
}
|
||||
self.property_animation
|
||||
.calculate_value(progress.min(1.0))
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -875,17 +864,30 @@ pub struct ElementAnimationSet {
|
|||
|
||||
/// The transitions for this element.
|
||||
pub transitions: Vec<Transition>,
|
||||
|
||||
/// Whether or not this ElementAnimationSet has had animations or transitions
|
||||
/// which have been added, removed, or had their state changed.
|
||||
pub dirty: bool,
|
||||
}
|
||||
|
||||
impl ElementAnimationSet {
|
||||
/// Cancel all animations in this `ElementAnimationSet`. This is typically called
|
||||
/// when the element has been removed from the DOM.
|
||||
pub fn cancel_all_animations(&mut self) {
|
||||
self.dirty = !self.animations.is_empty();
|
||||
for animation in self.animations.iter_mut() {
|
||||
animation.state = AnimationState::Canceled;
|
||||
}
|
||||
self.cancel_active_transitions();
|
||||
}
|
||||
|
||||
fn cancel_active_transitions(&mut self) {
|
||||
self.dirty = !self.transitions.is_empty();
|
||||
|
||||
for transition in self.transitions.iter_mut() {
|
||||
transition.state = AnimationState::Canceled;
|
||||
if transition.state != AnimationState::Finished {
|
||||
transition.state = AnimationState::Canceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,12 +896,18 @@ impl ElementAnimationSet {
|
|||
context: &SharedStyleContext,
|
||||
style: &mut Arc<ComputedValues>,
|
||||
) {
|
||||
for animation in &self.animations {
|
||||
animation.update_style(context, style);
|
||||
let now = context.current_time_for_animations;
|
||||
let mutable_style = Arc::make_mut(style);
|
||||
if let Some(map) = self.get_value_map_for_active_animations(now) {
|
||||
for value in map.values() {
|
||||
value.set_in_style_for_servo(mutable_style);
|
||||
}
|
||||
}
|
||||
|
||||
for transition in &self.transitions {
|
||||
transition.update_style(context, style);
|
||||
if let Some(map) = self.get_value_map_for_active_transitions(now) {
|
||||
for value in map.values() {
|
||||
value.set_in_style_for_servo(mutable_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -978,6 +986,7 @@ impl ElementAnimationSet {
|
|||
/// when appropriate.
|
||||
pub fn update_transitions_for_new_style(
|
||||
&mut self,
|
||||
might_need_transitions_update: bool,
|
||||
context: &SharedStyleContext,
|
||||
opaque_node: OpaqueNode,
|
||||
old_style: Option<&Arc<ComputedValues>>,
|
||||
|
@ -990,12 +999,18 @@ impl ElementAnimationSet {
|
|||
None => return,
|
||||
};
|
||||
|
||||
// If the style of this element is display:none, then cancel all active transitions.
|
||||
if after_change_style.get_box().clone_display().is_none() {
|
||||
self.cancel_active_transitions();
|
||||
return;
|
||||
}
|
||||
|
||||
if !might_need_transitions_update {
|
||||
return;
|
||||
}
|
||||
|
||||
// We convert old values into `before-change-style` here.
|
||||
// See https://drafts.csswg.org/css-transitions/#starting. We need to clone the
|
||||
// style because this might still be a reference to the original `old_style` and
|
||||
// we want to preserve that so that we can later properly calculate restyle damage.
|
||||
if self.has_active_transition() || self.has_active_animation() {
|
||||
before_change_style = before_change_style.clone();
|
||||
self.apply_active_animations(context, &mut before_change_style);
|
||||
}
|
||||
|
||||
|
@ -1016,6 +1031,7 @@ impl ElementAnimationSet {
|
|||
continue;
|
||||
}
|
||||
transition.state = AnimationState::Canceled;
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1086,6 +1102,45 @@ impl ElementAnimationSet {
|
|||
}
|
||||
|
||||
self.transitions.push(new_transition);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
/// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
|
||||
/// active transitions at the given time value.
|
||||
pub fn get_value_map_for_active_transitions(&self, now: f64) -> Option<AnimationValueMap> {
|
||||
if !self.has_active_transition() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut map =
|
||||
AnimationValueMap::with_capacity_and_hasher(self.transitions.len(), Default::default());
|
||||
for transition in &self.transitions {
|
||||
if transition.state == AnimationState::Canceled {
|
||||
continue;
|
||||
}
|
||||
let value = match transition.calculate_value(now) {
|
||||
Some(value) => value,
|
||||
None => continue,
|
||||
};
|
||||
map.insert(value.id(), value);
|
||||
}
|
||||
|
||||
Some(map)
|
||||
}
|
||||
|
||||
/// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
|
||||
/// active animations at the given time value.
|
||||
pub fn get_value_map_for_active_animations(&self, now: f64) -> Option<AnimationValueMap> {
|
||||
if !self.has_active_animation() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut map = Default::default();
|
||||
for animation in &self.animations {
|
||||
animation.get_property_declaration_at_time(now, &mut map);
|
||||
}
|
||||
|
||||
Some(map)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1098,13 +1153,6 @@ pub fn start_transitions_if_applicable(
|
|||
new_style: &Arc<ComputedValues>,
|
||||
animation_state: &mut ElementAnimationSet,
|
||||
) -> LonghandIdSet {
|
||||
// If the style of this element is display:none, then we don't start any transitions
|
||||
// and we cancel any currently running transitions by returning an empty LonghandIdSet.
|
||||
let box_style = new_style.get_box();
|
||||
if box_style.clone_display().is_none() {
|
||||
return LonghandIdSet::new();
|
||||
}
|
||||
|
||||
let mut properties_that_transition = LonghandIdSet::new();
|
||||
for transition in new_style.transition_properties() {
|
||||
let physical_property = transition.longhand_id.to_physical(new_style.writing_mode);
|
||||
|
@ -1214,6 +1262,8 @@ pub fn maybe_start_animations<E>(
|
|||
is_new: true,
|
||||
};
|
||||
|
||||
animation_state.dirty = true;
|
||||
|
||||
// If the animation was already present in the list for the node, just update its state.
|
||||
for existing_animation in animation_state.animations.iter_mut() {
|
||||
if existing_animation.state == AnimationState::Canceled {
|
||||
|
|
|
@ -479,23 +479,25 @@ pub trait TElement:
|
|||
/// Get the combined animation and transition rules.
|
||||
///
|
||||
/// FIXME(emilio): Is this really useful?
|
||||
fn animation_rules(&self) -> AnimationRules {
|
||||
fn animation_rules(&self, context: &SharedStyleContext) -> AnimationRules {
|
||||
if !self.may_have_animations() {
|
||||
return AnimationRules(None, None);
|
||||
}
|
||||
|
||||
AnimationRules(self.animation_rule(), self.transition_rule())
|
||||
AnimationRules(self.animation_rule(context), self.transition_rule(context))
|
||||
}
|
||||
|
||||
/// Get this element's animation rule.
|
||||
fn animation_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||
None
|
||||
}
|
||||
fn animation_rule(
|
||||
&self,
|
||||
_: &SharedStyleContext,
|
||||
) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
|
||||
|
||||
/// Get this element's transition rule.
|
||||
fn transition_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||
None
|
||||
}
|
||||
fn transition_rule(
|
||||
&self,
|
||||
context: &SharedStyleContext,
|
||||
) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
|
||||
|
||||
/// Get this element's state, for non-tree-structural pseudos.
|
||||
fn state(&self) -> ElementState;
|
||||
|
@ -729,9 +731,7 @@ pub trait TElement:
|
|||
/// In Gecko, element has a flag that represents the element may have
|
||||
/// any type of animations or not to bail out animation stuff early.
|
||||
/// Whereas Servo doesn't have such flag.
|
||||
fn may_have_animations(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn may_have_animations(&self) -> bool;
|
||||
|
||||
/// Creates a task to update various animation state on a given (pseudo-)element.
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -748,14 +748,14 @@ pub trait TElement:
|
|||
/// Returns true if the element has relevant animations. Relevant
|
||||
/// animations are those animations that are affecting the element's style
|
||||
/// or are scheduled to do so in the future.
|
||||
fn has_animations(&self) -> bool;
|
||||
fn has_animations(&self, context: &SharedStyleContext) -> bool;
|
||||
|
||||
/// Returns true if the element has a CSS animation.
|
||||
fn has_css_animations(&self, context: &SharedStyleContext) -> bool;
|
||||
|
||||
/// Returns true if the element has a CSS transition (including running transitions and
|
||||
/// completed transitions).
|
||||
fn has_css_transitions(&self) -> bool;
|
||||
fn has_css_transitions(&self, context: &SharedStyleContext) -> bool;
|
||||
|
||||
/// Returns true if the element has animation restyle hints.
|
||||
fn has_animation_restyle_hints(&self) -> bool {
|
||||
|
|
|
@ -1524,32 +1524,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
self.may_have_animations() && unsafe { Gecko_ElementHasCSSAnimations(self.0) }
|
||||
}
|
||||
|
||||
fn has_css_transitions(&self) -> bool {
|
||||
fn has_css_transitions(&self, _: &SharedStyleContext) -> bool {
|
||||
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
|
||||
}
|
||||
|
||||
fn might_need_transitions_update(
|
||||
&self,
|
||||
old_style: Option<&ComputedValues>,
|
||||
new_style: &ComputedValues,
|
||||
) -> bool {
|
||||
let old_style = match old_style {
|
||||
Some(v) => v,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let new_box_style = new_style.get_box();
|
||||
if !self.has_css_transitions() && !new_box_style.specifies_transitions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if new_box_style.clone_display().is_none() || old_style.clone_display().is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Detect if there are any changes that require us to update transitions.
|
||||
// This is used as a more thoroughgoing check than the, cheaper
|
||||
// might_need_transitions_update check.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use crate::computed_value_flags::ComputedValueFlags;
|
||||
use crate::context::{ElementCascadeInputs, QuirksMode, SelectorFlagsMap};
|
||||
use crate::context::{CascadeInputs, ElementCascadeInputs, QuirksMode, SelectorFlagsMap};
|
||||
use crate::context::{SharedStyleContext, StyleContext};
|
||||
use crate::data::ElementData;
|
||||
use crate::dom::TElement;
|
||||
|
@ -176,7 +176,9 @@ trait PrivateMatchMethods: TElement {
|
|||
if replacements.contains(RestyleHint::RESTYLE_CSS_TRANSITIONS) {
|
||||
replace_rule_node(
|
||||
CascadeLevel::Transitions,
|
||||
self.transition_rule().as_ref().map(|a| a.borrow_arc()),
|
||||
self.transition_rule(&context.shared)
|
||||
.as_ref()
|
||||
.map(|a| a.borrow_arc()),
|
||||
primary_rules,
|
||||
);
|
||||
}
|
||||
|
@ -184,7 +186,9 @@ trait PrivateMatchMethods: TElement {
|
|||
if replacements.contains(RestyleHint::RESTYLE_CSS_ANIMATIONS) {
|
||||
replace_rule_node(
|
||||
CascadeLevel::Animations,
|
||||
self.animation_rule().as_ref().map(|a| a.borrow_arc()),
|
||||
self.animation_rule(&context.shared)
|
||||
.as_ref()
|
||||
.map(|a| a.borrow_arc()),
|
||||
primary_rules,
|
||||
);
|
||||
}
|
||||
|
@ -194,14 +198,11 @@ trait PrivateMatchMethods: TElement {
|
|||
}
|
||||
|
||||
/// If there is no transition rule in the ComputedValues, it returns None.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn after_change_style(
|
||||
&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
primary_style: &Arc<ComputedValues>,
|
||||
) -> Option<Arc<ComputedValues>> {
|
||||
use crate::context::CascadeInputs;
|
||||
|
||||
let rule_node = primary_style.rules();
|
||||
let without_transition_rules = context
|
||||
.shared
|
||||
|
@ -314,6 +315,29 @@ trait PrivateMatchMethods: TElement {
|
|||
false
|
||||
}
|
||||
|
||||
fn might_need_transitions_update(
|
||||
&self,
|
||||
context: &StyleContext<Self>,
|
||||
old_style: Option<&ComputedValues>,
|
||||
new_style: &ComputedValues,
|
||||
) -> bool {
|
||||
let old_style = match old_style {
|
||||
Some(v) => v,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let new_box_style = new_style.get_box();
|
||||
if !self.has_css_transitions(context.shared) && !new_box_style.specifies_transitions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if new_box_style.clone_display().is_none() || old_style.clone_display().is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Create a SequentialTask for resolving descendants in a SMIL display
|
||||
/// property animation if the display property changed from none.
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -374,10 +398,12 @@ trait PrivateMatchMethods: TElement {
|
|||
tasks.insert(UpdateAnimationsTasks::CSS_ANIMATIONS);
|
||||
}
|
||||
|
||||
let before_change_style = if self
|
||||
.might_need_transitions_update(old_values.as_ref().map(|s| &**s), new_values)
|
||||
{
|
||||
let after_change_style = if self.has_css_transitions() {
|
||||
let before_change_style = if self.might_need_transitions_update(
|
||||
context,
|
||||
old_values.as_ref().map(|s| &**s),
|
||||
new_values,
|
||||
) {
|
||||
let after_change_style = if self.has_css_transitions(context.shared) {
|
||||
self.after_change_style(context, new_values)
|
||||
} else {
|
||||
None
|
||||
|
@ -445,6 +471,16 @@ trait PrivateMatchMethods: TElement {
|
|||
// map because this call will do a RwLock::read().
|
||||
let needs_animations_update =
|
||||
self.needs_animations_update(context, old_values.as_ref().map(|s| &**s), new_values);
|
||||
let might_need_transitions_update = self.might_need_transitions_update(
|
||||
context,
|
||||
old_values.as_ref().map(|s| &**s),
|
||||
new_values,
|
||||
);
|
||||
|
||||
let mut after_change_style = None;
|
||||
if might_need_transitions_update {
|
||||
after_change_style = self.after_change_style(context, new_values);
|
||||
}
|
||||
|
||||
let this_opaque = self.as_node().opaque();
|
||||
let shared_context = context.shared;
|
||||
|
@ -474,28 +510,43 @@ trait PrivateMatchMethods: TElement {
|
|||
}
|
||||
|
||||
animation_set.update_transitions_for_new_style(
|
||||
might_need_transitions_update,
|
||||
&shared_context,
|
||||
this_opaque,
|
||||
old_values.as_ref(),
|
||||
new_values,
|
||||
after_change_style.as_ref().unwrap_or(new_values),
|
||||
);
|
||||
|
||||
animation_set.apply_active_animations(shared_context, new_values);
|
||||
|
||||
// We clear away any finished transitions, but retain animations, because they
|
||||
// might still be used for proper calculation of `animation-fill-mode`.
|
||||
// might still be used for proper calculation of `animation-fill-mode`. This
|
||||
// should change the computed values in the style, so we don't need to mark
|
||||
// this set as dirty.
|
||||
animation_set
|
||||
.transitions
|
||||
.retain(|transition| transition.state != AnimationState::Finished);
|
||||
|
||||
// If the ElementAnimationSet is empty, and don't store it in order to
|
||||
// save memory and to avoid extra processing later.
|
||||
let changed_animations = animation_set.dirty;
|
||||
if !animation_set.is_empty() {
|
||||
animation_set.dirty = false;
|
||||
shared_context
|
||||
.animation_states
|
||||
.write()
|
||||
.insert(this_opaque, animation_set);
|
||||
}
|
||||
|
||||
// If we have modified animation or transitions, we recascade style for this node.
|
||||
if changed_animations {
|
||||
let mut resolver = StyleResolverForElement::new(
|
||||
*self,
|
||||
context,
|
||||
RuleInclusion::All,
|
||||
PseudoElementResolution::IfApplicable,
|
||||
);
|
||||
let new_primary = resolver.resolve_style_with_default_parents();
|
||||
*new_values = new_primary.primary.style.0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes and applies non-redundant damage.
|
||||
|
|
|
@ -2829,11 +2829,12 @@ pub mod style_structs {
|
|||
/// Returns whether there are any transitions specified.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn specifies_transitions(&self) -> bool {
|
||||
// TODO(mrobinson): This should check the combined duration and not just
|
||||
// the duration.
|
||||
self.transition_duration_iter()
|
||||
.take(self.transition_property_count())
|
||||
.any(|t| t.seconds() > 0.)
|
||||
(0..self.transition_property_count()).any(|index| {
|
||||
let combined_duration =
|
||||
self.transition_duration_mod(index).seconds().max(0.) +
|
||||
self.transition_delay_mod(index).seconds();
|
||||
combined_duration > 0.
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns true if animation properties are equal between styles, but without
|
||||
|
|
|
@ -587,6 +587,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
|||
style: &PrimaryStyle,
|
||||
validation_data_holder: Option<&mut StyleSharingTarget<E>>,
|
||||
dom_depth: usize,
|
||||
shared_context: &SharedStyleContext,
|
||||
) {
|
||||
let parent = match element.traversal_parent() {
|
||||
Some(element) => element,
|
||||
|
@ -619,7 +620,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
|||
// * Our computed style can still be affected by animations after we no
|
||||
// longer match any animation rules, since removing animations involves
|
||||
// a sequential task and an additional traversal.
|
||||
if element.has_animations() {
|
||||
if element.has_animations(shared_context) {
|
||||
debug!("Failing to insert to the cache: running animations");
|
||||
return;
|
||||
}
|
||||
|
@ -700,6 +701,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
|||
bloom_filter,
|
||||
nth_index_cache,
|
||||
selector_flags_map,
|
||||
shared_context,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -711,6 +713,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
|||
bloom: &StyleBloom<E>,
|
||||
nth_index_cache: &mut NthIndexCache,
|
||||
selector_flags_map: &mut SelectorFlagsMap<E>,
|
||||
shared_context: &SharedStyleContext,
|
||||
) -> Option<ResolvedElementStyles> {
|
||||
debug_assert!(!target.is_in_native_anonymous_subtree());
|
||||
|
||||
|
@ -770,7 +773,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if target.element.has_animations() {
|
||||
if target.element.has_animations(shared_context) {
|
||||
trace!("Miss: Has Animations");
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -433,7 +433,7 @@ where
|
|||
implemented_pseudo.as_ref(),
|
||||
self.element.style_attribute(),
|
||||
self.element.smil_override(),
|
||||
self.element.animation_rules(),
|
||||
self.element.animation_rules(self.context.shared),
|
||||
self.rule_inclusion,
|
||||
&mut applicable_declarations,
|
||||
&mut matching_context,
|
||||
|
|
|
@ -613,6 +613,7 @@ where
|
|||
&new_styles.primary,
|
||||
Some(&mut target),
|
||||
traversal_data.current_dom_depth,
|
||||
&context.shared,
|
||||
);
|
||||
|
||||
new_styles
|
||||
|
@ -669,6 +670,7 @@ where
|
|||
&new_styles.primary,
|
||||
None,
|
||||
traversal_data.current_dom_depth,
|
||||
&context.shared,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче