Bug 1344966 - Introduce eRestyle_CSSAnimations. r?heycam draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Sat, 25 Mar 2017 12:47:51 +0900
changeset 551275 3c45d95cbb21a6ccf6270e1028c072de25425507
parent 551274 a416429a2908492eb51471273d0ed2e970b955fc
child 551276 25e3ee85101a747627d8de2f214153744615affe
child 551280 abf0fd2b7c85d6e31a0ad8fcafc83ceb842974ff
push id51006
push userhikezoe@mozilla.com
push dateSat, 25 Mar 2017 09:59:39 +0000
reviewersheycam
bugs1344966
milestone55.0a1
Bug 1344966 - Introduce eRestyle_CSSAnimations. r?heycam RESTYLE_CSS_ANIMATIONS will be individually processed prior to other restyle hints in a traversal. MozReview-Commit-ID: Idrtj6oZ4yo
servo/components/style/data.rs
servo/components/style/matching.rs
servo/components/style/restyle_hints.rs
--- a/servo/components/style/data.rs
+++ b/servo/components/style/data.rs
@@ -4,17 +4,17 @@
 
 //! Per-node data used in style calculation.
 
 #![deny(missing_docs)]
 
 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;
 use std::fmt;
 use std::hash::BuildHasherDefault;
 use std::ops::{Deref, DerefMut};
 use std::sync::Arc;
 use stylist::Stylist;
@@ -131,17 +131,22 @@ impl ElementStyles {
 /// We wrap it in a newtype to force the encapsulation of the complexity of
 /// handling the correct invalidations in this file.
 #[derive(Clone, Debug)]
 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()
         })
     }
 
     /// Creates an empty `StoredRestyleHint`.
     pub fn empty() -> Self {
@@ -169,16 +174,26 @@ impl StoredRestyleHint {
     pub fn is_empty(&self) -> bool {
         self.0.is_empty()
     }
 
     /// Insert another restyle hint, effectively resulting in the union of both.
     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 {
     fn default() -> Self {
         StoredRestyleHint::empty()
     }
 }
 
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -12,17 +12,17 @@ use animation::{self, Animation, Propert
 use atomic_refcell::AtomicRefMut;
 use cache::{LRUCache, LRUCacheMutIterator};
 use cascade_info::CascadeInfo;
 use context::{SequentialTask, SharedStyleContext, StyleContext};
 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;
 use selectors::bloom::BloomFilter;
 use selectors::matching::{ElementSelectorFlags, StyleRelations};
 use selectors::matching::AFFECTED_BY_PSEUDO_ELEMENTS;
 use servo_config::opts;
 use sink::ForgetfulSink;
@@ -952,39 +952,61 @@ pub trait MatchMethods : TElement {
     fn cascade_with_replacements(&self,
                                  hint: RestyleHint,
                                  context: &StyleContext<Self>,
                                  data: &mut AtomicRefMut<ElementData>)
                                  -> bool {
         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;
 
         {
             let mut replace_rule_node = |level: CascadeLevel,
                                          pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
                                          path: &mut StrongRuleNode| {
                 let new_node = context.shared.stylist.rule_tree
                     .update_rule_at_level(level, pdb, path, &context.shared.guards);
                 if let Some(n) = new_node {
                     *path = n;
                     rule_node_changed = true;
                 }
             };
 
-            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, _)|
+                    <Self as MatchAttr>::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,
                                   primary_rules);
                 replace_rule_node(CascadeLevel::StyleAttributeImportant,
                                   style_attribute,
                                   primary_rules);
+                // The per-pseudo rule nodes never change in this path.
             }
         }
 
         // The per-pseudo rule nodes never change in this path.
         rule_node_changed
     }
 
     /// Attempts to share a style with another node. This method is unsafe
--- a/servo/components/style/restyle_hints.rs
+++ b/servo/components/style/restyle_hints.rs
@@ -42,16 +42,21 @@ bitflags! {
         /// NB: In Gecko, we have RESTYLE_SUBTREE which is inclusive of self,
         /// but heycam isn't aware of a good reason for that.
         const RESTYLE_DESCENDANTS = 0x04,
 
         /// Rerun selector matching on all later siblings of the element and all
         /// 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.
         const RESTYLE_STYLE_ATTRIBUTE = 0x40,
     }
 }
 
 /// Asserts that all RestyleHint flags have a matching nsRestyleHint value.
@@ -76,25 +81,26 @@ pub fn assert_restyle_hints_match() {
     check_restyle_hints! {
         nsRestyleHint_eRestyle_Self => RESTYLE_SELF,
         // Note that eRestyle_Subtree means "self and descendants", while
         // RESTYLE_DESCENDANTS means descendants only.  The From impl
         // below handles converting eRestyle_Subtree into
         // (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,
     }
 }
 
 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
     }
 }
 
 #[cfg(feature = "gecko")]
 impl From<nsRestyleHint> for RestyleHint {
     fn from(raw: nsRestyleHint) -> Self {
         use std::mem;
         let raw_bits: u32 = unsafe { mem::transmute(raw) };