Bug 1355348 - Add SMIL override cascade level; r?heycam draft
authorBrian Birtles <birtles@gmail.com>
Wed, 26 Apr 2017 12:59:31 +0900
changeset 568395 1ae64307252e077a0e39720781b85d27a0bc9cdb
parent 568394 a20adfbc8ea50f59bf420a99d494d40fa709bcee
child 568396 d1f31c3bd27f3333561bf26945cf2e244076a4c8
push id55859
push userbbirtles@mozilla.com
push dateWed, 26 Apr 2017 04:45:43 +0000
reviewersheycam
bugs1355348
milestone55.0a1
Bug 1355348 - Add SMIL override cascade level; r?heycam MozReview-Commit-ID: 5utyWI1LkcF
servo/components/style/dom.rs
servo/components/style/matching.rs
servo/components/style/rule_tree/mod.rs
servo/components/style/stylist.rs
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -314,16 +314,21 @@ pub trait TElement : Eq + PartialEq + De
         } else {
             self.parent_element()
         }
     }
 
     /// Get this element's style attribute.
     fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>>;
 
+    /// Get this element's SMIL override declarations.
+    fn get_smil_override(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
+        None
+    }
+
     /// Get this element's animation rules.
     fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules {
         AnimationRules(None, None)
     }
 
     /// Get this element's animation rule by the cascade level.
     fn get_animation_rule_by_cascade(&self,
                                      _pseudo: Option<&PseudoElement>,
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -877,29 +877,31 @@ pub trait MatchMethods : TElement {
                      relations: &mut StyleRelations)
                      -> bool
     {
         let mut applicable_declarations =
             Vec::<ApplicableDeclarationBlock>::with_capacity(16);
 
         let stylist = &context.shared.stylist;
         let style_attribute = self.style_attribute();
+        let smil_override = self.get_smil_override();
         let animation_rules = self.get_animation_rules(None);
         let mut rule_nodes_changed = false;
         let bloom = context.thread_local.bloom_filter.filter();
 
         let map = &mut context.thread_local.selector_flags;
         let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
             self.apply_selector_flags(map, element, flags);
         };
 
         // Compute the primary rule node.
         *relations = stylist.push_applicable_declarations(self,
                                                           Some(bloom),
                                                           style_attribute,
+                                                          smil_override,
                                                           animation_rules,
                                                           None,
                                                           &context.shared.guards,
                                                           &mut applicable_declarations,
                                                           &mut set_selector_flags);
 
         let primary_rule_node =
             compute_rule_node::<Self>(&stylist.rule_tree, &mut applicable_declarations);
@@ -947,17 +949,19 @@ pub trait MatchMethods : TElement {
             debug_assert!(applicable_declarations.is_empty());
             let pseudo_animation_rules = if pseudo.is_before_or_after() {
                 self.get_animation_rules(Some(&pseudo))
             } else {
                 AnimationRules(None, None)
             };
             stylist.push_applicable_declarations(self,
                                                  Some(bloom_filter),
-                                                 None, pseudo_animation_rules,
+                                                 None,
+                                                 None,
+                                                 pseudo_animation_rules,
                                                  Some(&pseudo),
                                                  &guards,
                                                  &mut applicable_declarations,
                                                  &mut set_selector_flags);
 
             if !applicable_declarations.is_empty() {
                 let new_rules =
                     compute_rule_node::<Self>(rule_tree, &mut applicable_declarations);
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -249,28 +249,30 @@ impl RuleTree {
         // 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.
+    /// Returns new rule node without rules from declarative animations.
     pub fn remove_animation_and_transition_rules(&self, path: &StrongRuleNode) -> StrongRuleNode {
-        // Return a clone if there is neither animation nor transition level.
+        // Return a clone if there are no animation rules.
         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 iter = path.self_and_ancestors().take_while(
+            |node| node.cascade_level() >= CascadeLevel::SMILOverride);
         let mut last = path;
         let mut children = vec![];
         for node in iter {
-            if node.cascade_level() != CascadeLevel::Animations &&
+            if node.cascade_level() != CascadeLevel::SMILOverride &&
+               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())
     }
@@ -296,16 +298,18 @@ pub enum CascadeLevel {
     /// Presentational hints.
     PresHints,
     /// User normal rules.
     UserNormal,
     /// Author normal rules.
     AuthorNormal,
     /// Style attribute normal rules.
     StyleAttributeNormal,
+    /// SVG SMIL animations.
+    SMILOverride,
     /// CSS animations and script-generated animations.
     Animations,
     /// Author-supplied important rules.
     AuthorImportant,
     /// Style attribute important rules.
     StyleAttributeImportant,
     /// User important rules.
     UserImportant,
@@ -328,16 +332,17 @@ impl CascadeLevel {
     }
 
     /// Returns whether this cascade level is unique per element, in which case
     /// we can replace the path in the cascade without fear.
     pub fn is_unique_per_element(&self) -> bool {
         match *self {
             CascadeLevel::Transitions |
             CascadeLevel::Animations |
+            CascadeLevel::SMILOverride |
             CascadeLevel::StyleAttributeNormal |
             CascadeLevel::StyleAttributeImportant => true,
             _ => false,
         }
     }
 
     /// Returns whether this cascade level represents important rules of some
     /// sort.
@@ -775,18 +780,21 @@ impl StrongRuleNode {
         if self.get().free_count.load(Ordering::Relaxed) > RULE_TREE_GC_INTERVAL {
             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))
+            .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride)
+            .any(|node| matches!(node.cascade_level(),
+                                 CascadeLevel::SMILOverride |
+                                 CascadeLevel::Animations |
+                                 CascadeLevel::Transitions))
     }
 }
 
 /// An iterator over a rule node and its ancestors.
 #[derive(Clone)]
 pub struct SelfAndAncestors<'a> {
     current: Option<&'a StrongRuleNode>,
 }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -507,16 +507,17 @@ impl Stylist {
                 }
             }
         };
 
 
         self.push_applicable_declarations(element,
                                           None,
                                           None,
+                                          None,
                                           AnimationRules(None, None),
                                           Some(pseudo),
                                           guards,
                                           &mut declarations,
                                           &mut set_selector_flags);
 
         let rule_node =
             self.rule_tree.insert_ordered_rules(
@@ -626,16 +627,17 @@ impl Stylist {
     ///
     /// The returned `StyleRelations` indicate hints about which kind of rules
     /// have matched.
     pub fn push_applicable_declarations<E, V, F>(
                                         &self,
                                         element: &E,
                                         parent_bf: Option<&BloomFilter>,
                                         style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
+                                        smil_override: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
                                         animation_rules: AnimationRules,
                                         pseudo_element: Option<&PseudoElement>,
                                         guards: &StylesheetGuards,
                                         applicable_declarations: &mut V,
                                         flags_setter: &mut F)
                                         -> StyleRelations
         where E: TElement +
                  fmt::Debug +
@@ -706,74 +708,84 @@ impl Stylist {
                         applicable_declarations,
                         ApplicableDeclarationBlock::from_declarations(sa.clone(),
                                                                       CascadeLevel::StyleAttributeNormal));
                 }
             }
 
             debug!("style attr: {:?}", relations);
 
-            // Step 5: Animations.
+            // Step 5: SMIL override.
+            // Declarations from SVG SMIL animation elements.
+            if let Some(so) = smil_override {
+                Push::push(
+                    applicable_declarations,
+                    ApplicableDeclarationBlock::from_declarations(so.clone(),
+                                                                  CascadeLevel::SMILOverride));
+            }
+            debug!("SMIL: {:?}", relations);
+
+            // Step 6: Animations.
             // The animations sheet (CSS animations, script-generated animations,
             // and CSS transitions that are no longer tied to CSS markup)
             if let Some(anim) = animation_rules.0 {
                 Push::push(
                     applicable_declarations,
                     ApplicableDeclarationBlock::from_declarations(anim.clone(),
                                                                   CascadeLevel::Animations));
             }
             debug!("animation: {:?}", relations);
 
-            // Step 6: Author-supplied `!important` rules.
+            // Step 7: Author-supplied `!important` rules.
             map.author.get_all_matching_rules(element,
                                               parent_bf,
                                               applicable_declarations,
                                               &mut relations,
                                               flags_setter,
                                               CascadeLevel::AuthorImportant);
 
             debug!("author important: {:?}", relations);
 
-            // Step 7: `!important` style attributes.
+            // Step 8: `!important` style attributes.
             if let Some(sa) = style_attribute {
                 if sa.read_with(guards.author).any_important() {
                     relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
                     Push::push(
                         applicable_declarations,
                         ApplicableDeclarationBlock::from_declarations(sa.clone(),
                                                                       CascadeLevel::StyleAttributeImportant));
                 }
             }
 
             debug!("style attr important: {:?}", relations);
 
-            // Step 8: User `!important` rules.
+            // Step 9: User `!important` rules.
             map.user.get_all_matching_rules(element,
                                             parent_bf,
                                             applicable_declarations,
                                             &mut relations,
                                             flags_setter,
                                             CascadeLevel::UserImportant);
 
             debug!("user important: {:?}", relations);
         } else {
             debug!("skipping non-agent rules");
         }
 
-        // Step 9: UA `!important` rules.
+        // Step 10: UA `!important` rules.
         map.user_agent.get_all_matching_rules(element,
                                               parent_bf,
                                               applicable_declarations,
                                               &mut relations,
                                               flags_setter,
                                               CascadeLevel::UAImportant);
 
         debug!("UA important: {:?}", relations);
 
-        // Step 10: Transitions.
+        // Step 11: Transitions.
         // The transitions sheet (CSS transitions that are tied to CSS markup)
         if let Some(anim) = animation_rules.1 {
             Push::push(
                 applicable_declarations,
                 ApplicableDeclarationBlock::from_declarations(anim.clone(), CascadeLevel::Transitions));
         }
         debug!("transition: {:?}", relations);