diff --git a/components/style/matching.rs b/components/style/matching.rs index 8820108766a..33905e0aebb 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -469,24 +469,15 @@ trait PrivateMatchMethods: TElement { } } - fn cascade_internal(&self, - context: &StyleContext, - primary_style: &ComputedStyle, - pseudo_style: &mut Option<(&PseudoElement, &mut ComputedStyle)>, - booleans: &CascadeBooleans) - -> Arc { + fn cascade_with_rules(&self, + context: &StyleContext, + rule_node: &StrongRuleNode, + primary_style: &ComputedStyle, + pseudo_style: &Option<(&PseudoElement, &mut ComputedStyle)>, + cascade_flags: CascadeFlags) + -> Arc { let shared_context = context.shared; let mut cascade_info = CascadeInfo::new(); - let mut cascade_flags = CascadeFlags::empty(); - if booleans.shareable { - cascade_flags.insert(SHAREABLE) - } - if self.skip_root_and_item_based_display_fixup() { - cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) - } - - // Grab the rule node. - let rule_node = &pseudo_style.as_ref().map_or(primary_style, |p| &*p.1).rules; // Grab the inherited values. let parent_el; @@ -552,6 +543,25 @@ trait PrivateMatchMethods: TElement { values } + fn cascade_internal(&self, + context: &StyleContext, + primary_style: &ComputedStyle, + pseudo_style: &Option<(&PseudoElement, &mut ComputedStyle)>, + booleans: &CascadeBooleans) + -> Arc { + let mut cascade_flags = CascadeFlags::empty(); + if booleans.shareable { + cascade_flags.insert(SHAREABLE) + } + if self.skip_root_and_item_based_display_fixup() { + cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) + } + + // Grab the rule node. + let rule_node = &pseudo_style.as_ref().map_or(primary_style, |p| &*p.1).rules; + self.cascade_with_rules(context, rule_node, primary_style, pseudo_style, cascade_flags) + } + /// Computes values and damage for the primary or pseudo style of an element, /// setting them on the ElementData. fn cascade_primary_or_pseudo<'a>(&self, @@ -570,7 +580,7 @@ trait PrivateMatchMethods: TElement { // Compute the new values. let mut new_values = self.cascade_internal(context, primary_style, - &mut pseudo_style, &booleans); + &pseudo_style, &booleans); // Handle animations. if booleans.animate { @@ -594,6 +604,33 @@ trait PrivateMatchMethods: TElement { } } + #[cfg(feature = "gecko")] + fn get_after_change_style(&self, + context: &mut StyleContext, + primary_style: &ComputedStyle, + pseudo_style: &Option<(&PseudoElement, &mut ComputedStyle)>) + -> Arc { + let style = &pseudo_style.as_ref().map_or(primary_style, |p| &*p.1); + let rule_node = &style.rules; + let without_transition_rules = + context.shared.stylist.rule_tree.remove_transition_rule_if_applicable(rule_node); + if without_transition_rules == *rule_node { + // Note that unwrapping here is fine, because the style is + // only incomplete during the styling process. + return style.values.as_ref().unwrap().clone(); + } + + let mut cascade_flags = CascadeFlags::empty(); + if self.skip_root_and_item_based_display_fixup() { + cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) + } + self.cascade_with_rules(context, + &without_transition_rules, + primary_style, + &pseudo_style, + cascade_flags) + } + #[cfg(feature = "gecko")] fn process_animations(&self, context: &mut StyleContext, diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 54cf785e458..53a78ac2cad 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -239,6 +239,37 @@ impl RuleTree { // necessary. Some(self.insert_ordered_rules_from(current, children.into_iter().rev())) } + + /// Returns new rule nodes without Transitions level rule. + pub fn remove_transition_rule_if_applicable(&self, path: &StrongRuleNode) -> StrongRuleNode { + // Return a clone if there is no transition level. + if path.cascade_level() != CascadeLevel::Transitions { + return path.clone(); + } + + path.parent().unwrap().clone() + } + + /// Returns new rule node without Animations and Transitions level rules. + pub fn remove_animation_and_transition_rules(&self, path: &StrongRuleNode) -> StrongRuleNode { + // Return a clone if there is neither animation nor transition level. + if !path.has_animation_or_transition_rules() { + return path.clone(); + } + + let iter = path.self_and_ancestors().take_while(|node| node.cascade_level() >= CascadeLevel::Animations); + let mut last = path; + let mut children = vec![]; + for node in iter { + if node.cascade_level() != CascadeLevel::Animations && + node.cascade_level() != CascadeLevel::Transitions { + children.push((node.get().source.clone().unwrap(), node.cascade_level())); + } + last = node; + } + + self.insert_ordered_rules_from(last.parent().unwrap().clone(), children.into_iter().rev()) + } } /// The number of RuleNodes added to the free list before we will consider @@ -728,6 +759,13 @@ impl StrongRuleNode { self.gc(); } } + + /// Returns true if there is either animation or transition level rule. + pub fn has_animation_or_transition_rules(&self) -> bool { + self.self_and_ancestors() + .take_while(|node| node.cascade_level() >= CascadeLevel::Animations) + .any(|node| matches!(node.cascade_level(), CascadeLevel::Animations | CascadeLevel::Transitions)) + } } /// An iterator over a rule node and its ancestors.