Bug 1355348 - Add SMIL override cascade level; r?heycam
MozReview-Commit-ID: 5utyWI1LkcF
--- 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);