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
--- 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) };