mirror of
https://github.com/servo/servo.git
synced 2025-06-24 17:14:33 +01:00
Bug 1341372 - Part 1: Let animation-only restyle include css-transition.
Animation-only restyle should include both Animation and Transition cascade levels. MozReview-Commit-ID: 5l6gaJKbixM
This commit is contained in:
parent
485a4de729
commit
1c1e487491
6 changed files with 77 additions and 24 deletions
|
@ -9,7 +9,7 @@
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use properties::longhands::display::computed_value as display;
|
use properties::longhands::display::computed_value as display;
|
||||||
use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage, Snapshot};
|
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage, Snapshot};
|
||||||
#[cfg(feature = "servo")] use std::collections::HashMap;
|
#[cfg(feature = "servo")] use std::collections::HashMap;
|
||||||
|
@ -199,13 +199,13 @@ impl StoredRestyleHint {
|
||||||
// In the middle of an animation only restyle, we don't need to
|
// In the middle of an animation only restyle, we don't need to
|
||||||
// propagate any restyle hints, and we need to remove ourselves.
|
// propagate any restyle hints, and we need to remove ourselves.
|
||||||
if traversal_flags.for_animation_only() {
|
if traversal_flags.for_animation_only() {
|
||||||
if self.0.contains(RESTYLE_CSS_ANIMATIONS) {
|
if self.0.intersects(RestyleHint::for_animations()) {
|
||||||
self.0.remove(RESTYLE_CSS_ANIMATIONS);
|
self.0.remove(RestyleHint::for_animations());
|
||||||
}
|
}
|
||||||
return Self::empty();
|
return Self::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(!self.0.contains(RESTYLE_CSS_ANIMATIONS),
|
debug_assert!(!self.0.intersects(RestyleHint::for_animations()),
|
||||||
"There should not be any animation restyle hints \
|
"There should not be any animation restyle hints \
|
||||||
during normal traversal");
|
during normal traversal");
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ impl StoredRestyleHint {
|
||||||
|
|
||||||
/// Returns true if the hint has animation-only restyle.
|
/// Returns true if the hint has animation-only restyle.
|
||||||
pub fn has_animation_hint(&self) -> bool {
|
pub fn has_animation_hint(&self) -> bool {
|
||||||
self.0.contains(RESTYLE_CSS_ANIMATIONS)
|
self.0.intersects(RestyleHint::for_animations())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ use data::ElementData;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
use properties::{ComputedValues, PropertyDeclarationBlock};
|
use properties::{ComputedValues, PropertyDeclarationBlock};
|
||||||
|
use rule_tree::CascadeLevel;
|
||||||
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
|
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
|
||||||
use selectors::matching::ElementSelectorFlags;
|
use selectors::matching::ElementSelectorFlags;
|
||||||
use shared_lock::Locked;
|
use shared_lock::Locked;
|
||||||
|
@ -320,6 +321,14 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
||||||
AnimationRules(None, None)
|
AnimationRules(None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this element's animation rule by the cascade level.
|
||||||
|
fn get_animation_rule_by_cascade(&self,
|
||||||
|
_pseudo: Option<&PseudoElement>,
|
||||||
|
_cascade_level: CascadeLevel)
|
||||||
|
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Get this element's animation rule.
|
/// Get this element's animation rule.
|
||||||
fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
|
fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
|
|
|
@ -528,6 +528,17 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
self.get_transition_rule(pseudo))
|
self.get_transition_rule(pseudo))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_animation_rule_by_cascade(&self,
|
||||||
|
pseudo: Option<&PseudoElement>,
|
||||||
|
cascade_level: ServoCascadeLevel)
|
||||||
|
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
|
match cascade_level {
|
||||||
|
ServoCascadeLevel::Animations => self.get_animation_rule(pseudo),
|
||||||
|
ServoCascadeLevel::Transitions => self.get_transition_rule(pseudo),
|
||||||
|
_ => panic!("Unsupported cascade level for getting the animation rule")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
|
fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
get_animation_rule(self, pseudo, CascadeLevel::Animations)
|
get_animation_rule(self, pseudo, CascadeLevel::Animations)
|
||||||
|
|
|
@ -19,7 +19,7 @@ use dom::{AnimationRules, SendElement, TElement, TNode};
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
||||||
use properties::longhands::display::computed_value as display;
|
use properties::longhands::display::computed_value as display;
|
||||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint};
|
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS, RestyleHint};
|
||||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
||||||
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
|
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
|
||||||
use selectors::bloom::BloomFilter;
|
use selectors::bloom::BloomFilter;
|
||||||
|
@ -984,25 +984,44 @@ pub trait MatchMethods : TElement {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// RESTYLE_CSS_ANIMATIONS is processed prior to other restyle hints
|
// RESTYLE_CSS_ANIMATIONS or RESTYLE_CSS_TRANSITIONS is processed prior to other
|
||||||
// in the name of animation-only traversal. Rest of restyle hints
|
// restyle hints in the name of animation-only traversal. Rest of restyle hints
|
||||||
// will be processed in a subsequent normal traversal.
|
// will be processed in a subsequent normal traversal.
|
||||||
if hint.contains(RESTYLE_CSS_ANIMATIONS) {
|
if hint.intersects(RestyleHint::for_animations()) {
|
||||||
debug_assert!(context.shared.traversal_flags.for_animation_only());
|
debug_assert!(context.shared.traversal_flags.for_animation_only());
|
||||||
|
|
||||||
let animation_rule = self.get_animation_rule(None);
|
use data::EagerPseudoStyles;
|
||||||
replace_rule_node(CascadeLevel::Animations,
|
let mut replace_rule_node_for_animation = |level: CascadeLevel,
|
||||||
|
primary_rules: &mut StrongRuleNode,
|
||||||
|
pseudos: &mut EagerPseudoStyles| {
|
||||||
|
let animation_rule = self.get_animation_rule_by_cascade(None, level);
|
||||||
|
replace_rule_node(level,
|
||||||
animation_rule.as_ref(),
|
animation_rule.as_ref(),
|
||||||
primary_rules);
|
primary_rules);
|
||||||
|
|
||||||
let pseudos = &mut element_styles.pseudos;
|
|
||||||
for pseudo in pseudos.keys().iter().filter(|p| p.is_before_or_after()) {
|
for pseudo in pseudos.keys().iter().filter(|p| p.is_before_or_after()) {
|
||||||
let animation_rule = self.get_animation_rule(Some(&pseudo));
|
let animation_rule = self.get_animation_rule_by_cascade(Some(&pseudo), level);
|
||||||
let pseudo_rules = &mut pseudos.get_mut(&pseudo).unwrap().rules;
|
let pseudo_rules = &mut pseudos.get_mut(&pseudo).unwrap().rules;
|
||||||
replace_rule_node(CascadeLevel::Animations,
|
replace_rule_node(level,
|
||||||
animation_rule.as_ref(),
|
animation_rule.as_ref(),
|
||||||
pseudo_rules);
|
pseudo_rules);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply Transition rules and Animation rules if the corresponding restyle hint
|
||||||
|
// is contained.
|
||||||
|
let pseudos = &mut element_styles.pseudos;
|
||||||
|
if hint.contains(RESTYLE_CSS_TRANSITIONS) {
|
||||||
|
replace_rule_node_for_animation(CascadeLevel::Transitions,
|
||||||
|
primary_rules,
|
||||||
|
pseudos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if hint.contains(RESTYLE_CSS_ANIMATIONS) {
|
||||||
|
replace_rule_node_for_animation(CascadeLevel::Animations,
|
||||||
|
primary_rules,
|
||||||
|
pseudos);
|
||||||
|
}
|
||||||
} else if hint.contains(RESTYLE_STYLE_ATTRIBUTE) {
|
} else if hint.contains(RESTYLE_STYLE_ATTRIBUTE) {
|
||||||
let style_attribute = self.style_attribute();
|
let style_attribute = self.style_attribute();
|
||||||
replace_rule_node(CascadeLevel::StyleAttributeNormal,
|
replace_rule_node(CascadeLevel::StyleAttributeNormal,
|
||||||
|
|
|
@ -48,6 +48,11 @@ bitflags! {
|
||||||
/// of their descendants.
|
/// of their descendants.
|
||||||
const RESTYLE_LATER_SIBLINGS = 0x08,
|
const RESTYLE_LATER_SIBLINGS = 0x08,
|
||||||
|
|
||||||
|
/// Replace the style data coming from CSS transitions without updating
|
||||||
|
/// any other style data. This hint is only processed in animation-only
|
||||||
|
/// traversal which is prior to normal traversal.
|
||||||
|
const RESTYLE_CSS_TRANSITIONS = 0x10,
|
||||||
|
|
||||||
/// Replace the style data coming from CSS animations without updating
|
/// Replace the style data coming from CSS animations without updating
|
||||||
/// any other style data. This hint is only processed in animation-only
|
/// any other style data. This hint is only processed in animation-only
|
||||||
/// traversal which is prior to normal traversal.
|
/// traversal which is prior to normal traversal.
|
||||||
|
@ -87,6 +92,7 @@ pub fn assert_restyle_hints_match() {
|
||||||
// (RESTYLE_SELF | RESTYLE_DESCENDANTS).
|
// (RESTYLE_SELF | RESTYLE_DESCENDANTS).
|
||||||
nsRestyleHint_eRestyle_Subtree => RESTYLE_DESCENDANTS,
|
nsRestyleHint_eRestyle_Subtree => RESTYLE_DESCENDANTS,
|
||||||
nsRestyleHint_eRestyle_LaterSiblings => RESTYLE_LATER_SIBLINGS,
|
nsRestyleHint_eRestyle_LaterSiblings => RESTYLE_LATER_SIBLINGS,
|
||||||
|
nsRestyleHint_eRestyle_CSSTransitions => RESTYLE_CSS_TRANSITIONS,
|
||||||
nsRestyleHint_eRestyle_CSSAnimations => RESTYLE_CSS_ANIMATIONS,
|
nsRestyleHint_eRestyle_CSSAnimations => RESTYLE_CSS_ANIMATIONS,
|
||||||
nsRestyleHint_eRestyle_StyleAttribute => RESTYLE_STYLE_ATTRIBUTE,
|
nsRestyleHint_eRestyle_StyleAttribute => RESTYLE_STYLE_ATTRIBUTE,
|
||||||
}
|
}
|
||||||
|
@ -96,7 +102,12 @@ impl RestyleHint {
|
||||||
/// The subset hints that affect the styling of a single element during the
|
/// The subset hints that affect the styling of a single element during the
|
||||||
/// traversal.
|
/// traversal.
|
||||||
pub fn for_self() -> Self {
|
pub fn for_self() -> Self {
|
||||||
RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE | RESTYLE_CSS_ANIMATIONS
|
RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE | RESTYLE_CSS_ANIMATIONS | RESTYLE_CSS_TRANSITIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The subset hints that are used for animation restyle.
|
||||||
|
pub fn for_animations() -> Self {
|
||||||
|
RESTYLE_CSS_ANIMATIONS | RESTYLE_CSS_TRANSITIONS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1788,12 +1788,15 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
|
||||||
debug!("Servo_NoteExplicitHints: {:?}, restyle_hint={:?}, change_hint={:?}",
|
debug!("Servo_NoteExplicitHints: {:?}, restyle_hint={:?}, change_hint={:?}",
|
||||||
element, restyle_hint, change_hint);
|
element, restyle_hint, change_hint);
|
||||||
debug_assert!(restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations ||
|
debug_assert!(restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations ||
|
||||||
(restyle_hint.0 & structs::nsRestyleHint_eRestyle_CSSAnimations.0) == 0,
|
restyle_hint == structs::nsRestyleHint_eRestyle_CSSTransitions ||
|
||||||
"eRestyle_CSSAnimations should only appear by itself");
|
(restyle_hint.0 & (structs::nsRestyleHint_eRestyle_CSSAnimations.0 |
|
||||||
|
structs::nsRestyleHint_eRestyle_CSSTransitions.0)) == 0,
|
||||||
|
"eRestyle_CSSAnimations or eRestyle_CSSTransitions should only appear by itself");
|
||||||
|
|
||||||
let mut maybe_data = element.mutate_data();
|
let mut maybe_data = element.mutate_data();
|
||||||
let maybe_restyle_data = maybe_data.as_mut().and_then(|d| unsafe {
|
let maybe_restyle_data = maybe_data.as_mut().and_then(|d| unsafe {
|
||||||
maybe_restyle(d, element, restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations)
|
maybe_restyle(d, element, restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations ||
|
||||||
|
restyle_hint == structs::nsRestyleHint_eRestyle_CSSTransitions)
|
||||||
});
|
});
|
||||||
if let Some(restyle_data) = maybe_restyle_data {
|
if let Some(restyle_data) = maybe_restyle_data {
|
||||||
let restyle_hint: RestyleHint = restyle_hint.into();
|
let restyle_hint: RestyleHint = restyle_hint.into();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue