diff --git a/components/style/data.rs b/components/style/data.rs index 096cd78c0f9..5f714fcf99d 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -9,7 +9,7 @@ use dom::TElement; use properties::ComputedValues; use properties::longhands::display::computed_value as display; -use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; +use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; use rule_tree::StrongRuleNode; use selector_parser::{PseudoElement, RestyleDamage, Snapshot}; use std::collections::HashMap; @@ -136,7 +136,12 @@ pub struct StoredRestyleHint(RestyleHint); impl StoredRestyleHint { /// Propagates this restyle hint to a child element. pub fn propagate(&self) -> Self { - StoredRestyleHint(if self.0.contains(RESTYLE_DESCENDANTS) { + // If we have RESTYLE_CSS_ANIMATIONS restyle hint, it means we are in the + // middle of an animation only restyle. In that case, we don't need to + // propagate any restyle hints. + StoredRestyleHint(if self.0.contains(RESTYLE_CSS_ANIMATIONS) { + RestyleHint::empty() + } else if self.0.contains(RESTYLE_DESCENDANTS) { RESTYLE_SELF | RESTYLE_DESCENDANTS } else { RestyleHint::empty() @@ -174,6 +179,16 @@ impl StoredRestyleHint { pub fn insert(&mut self, other: &Self) { self.0 |= other.0 } + + /// Remove animation restyle hint. + pub fn remove_animation_hint(&mut self) { + self.0.remove(RESTYLE_CSS_ANIMATIONS) + } + + /// Returns true if the hint has animation-only restyle. + pub fn has_animation_hint(&self) -> bool { + self.0.contains(RESTYLE_CSS_ANIMATIONS) + } } impl Default for StoredRestyleHint { diff --git a/components/style/matching.rs b/components/style/matching.rs index 1df95531b48..c0eb82d9086 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -17,7 +17,7 @@ use data::{ComputedStyle, ElementData, ElementStyles, RestyleData}; use dom::{AnimationRules, SendElement, TElement, TNode}; use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; use properties::longhands::display::computed_value as display; -use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RestyleHint}; +use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode}; use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl}; use selectors::MatchAttr; @@ -957,7 +957,8 @@ pub trait MatchMethods : TElement { use properties::PropertyDeclarationBlock; use shared_lock::Locked; - let primary_rules = &mut data.styles_mut().primary.rules; + let element_styles = &mut data.styles_mut(); + let primary_rules = &mut element_styles.primary.rules; let mut rule_node_changed = false; { @@ -972,7 +973,27 @@ pub trait MatchMethods : TElement { } }; - if hint.contains(RESTYLE_STYLE_ATTRIBUTE) { + // RESTYLE_CSS_ANIMATIONS is processed prior to other restyle hints + // in the name of animation-only traversal. Rest of restyle hints + // will be processed in a subsequent normal traversal. + if hint.contains(RESTYLE_CSS_ANIMATIONS) { + debug_assert!(context.shared.animation_only_restyle); + + let animation_rule = self.get_animation_rule(None); + replace_rule_node(CascadeLevel::Animations, + animation_rule.as_ref(), + primary_rules); + + let iter = element_styles.pseudos.iter_mut().filter(|&(p, _)| + ::Impl::pseudo_is_before_or_after(p)); + for (pseudo, ref mut computed) in iter { + let animation_rule = self.get_animation_rule(Some(pseudo)); + let pseudo_rules = &mut computed.rules; + replace_rule_node(CascadeLevel::Animations, + animation_rule.as_ref(), + pseudo_rules); + } + } else if hint.contains(RESTYLE_STYLE_ATTRIBUTE) { let style_attribute = self.style_attribute(); replace_rule_node(CascadeLevel::StyleAttributeNormal, style_attribute, @@ -980,6 +1001,7 @@ pub trait MatchMethods : TElement { replace_rule_node(CascadeLevel::StyleAttributeImportant, style_attribute, primary_rules); + // The per-pseudo rule nodes never change in this path. } } diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index 76065e12578..c0827b788bb 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -47,6 +47,11 @@ bitflags! { /// of their descendants. const RESTYLE_LATER_SIBLINGS = 0x08, + /// Replace the style data coming from CSS animations without updating + /// any other style data. This hint is only processed in animation-only + /// traversal which is prior to normal traversal. + const RESTYLE_CSS_ANIMATIONS = 0x20, + /// Don't re-run selector-matching on the element, only the style /// attribute has changed, and this change didn't have any other /// dependencies. @@ -81,6 +86,7 @@ pub fn assert_restyle_hints_match() { // (RESTYLE_SELF | RESTYLE_DESCENDANTS). nsRestyleHint_eRestyle_Subtree => RESTYLE_DESCENDANTS, nsRestyleHint_eRestyle_LaterSiblings => RESTYLE_LATER_SIBLINGS, + nsRestyleHint_eRestyle_CSSAnimations => RESTYLE_CSS_ANIMATIONS, nsRestyleHint_eRestyle_StyleAttribute => RESTYLE_STYLE_ATTRIBUTE, } } @@ -89,7 +95,7 @@ impl RestyleHint { /// The subset hints that affect the styling of a single element during the /// traversal. pub fn for_self() -> Self { - RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE + RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE | RESTYLE_CSS_ANIMATIONS } }