Skip to content

Commit

Permalink
Bug 1331047: Implement the new traversal semantics for stylo. r=bholl…
Browse files Browse the repository at this point in the history
…ey,hiro

MozReview-Commit-ID: 4BXx9JpGZKX
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
  • Loading branch information
emilio committed Apr 27, 2017
1 parent 85ad961 commit be0139f
Show file tree
Hide file tree
Showing 11 changed files with 543 additions and 358 deletions.
12 changes: 6 additions & 6 deletions components/script/layout_wrapper.rs
Expand Up @@ -461,16 +461,16 @@ impl<'le> TElement for ServoLayoutElement<'le> {
self.element.has_selector_flags(flags)
}

fn has_animations(&self, _pseudo: Option<&PseudoElement>) -> bool {
panic!("this should be only called on gecko");
fn has_animations(&self) -> bool {
unreachable!("this should be only called on gecko");
}

fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool {
panic!("this should be only called on gecko");
fn has_css_animations(&self) -> bool {
unreachable!("this should be only called on gecko");
}

fn has_css_transitions(&self, _pseudo: Option<&PseudoElement>) -> bool {
panic!("this should be only called on gecko");
fn has_css_transitions(&self) -> bool {
unreachable!("this should be only called on gecko");
}
}

Expand Down
22 changes: 10 additions & 12 deletions components/style/context.rs
Expand Up @@ -20,7 +20,6 @@ use font_metrics::FontMetricsProvider;
use matching::StyleSharingCandidateCache;
use parking_lot::RwLock;
#[cfg(feature = "gecko")] use properties::ComputedValues;
#[cfg(feature = "gecko")] use selector_parser::PseudoElement;
use selectors::matching::ElementSelectorFlags;
#[cfg(feature = "servo")] use servo_config::opts;
use shared_lock::StylesheetGuards;
Expand Down Expand Up @@ -270,7 +269,8 @@ impl TraversalStatistics {

#[cfg(feature = "gecko")]
bitflags! {
/// Represents which tasks are performed in a SequentialTask of UpdateAnimations.
/// Represents which tasks are performed in a SequentialTask of
/// UpdateAnimations.
pub flags UpdateAnimationsTasks: u8 {
/// Update CSS Animations.
const CSS_ANIMATIONS = structs::UpdateAnimationsTasks_CSSAnimations,
Expand All @@ -296,10 +296,8 @@ pub enum SequentialTask<E: TElement> {
/// of the non-animation style traversal, and updating the computed effect properties.
#[cfg(feature = "gecko")]
UpdateAnimations {
/// The target element.
/// The target element or pseudo-element.
el: SendElement<E>,
/// The target pseudo element.
pseudo: Option<PseudoElement>,
/// The before-change style for transitions. We use before-change style as the initial
/// value of its Keyframe. Required if |tasks| includes CSSTransitions.
before_change_style: Option<Arc<ComputedValues>>,
Expand All @@ -316,8 +314,8 @@ impl<E: TElement> SequentialTask<E> {
match self {
Unused(_) => unreachable!(),
#[cfg(feature = "gecko")]
UpdateAnimations { el, pseudo, before_change_style, tasks } => {
unsafe { el.update_animations(pseudo.as_ref(), before_change_style, tasks) };
UpdateAnimations { el, before_change_style, tasks } => {
unsafe { el.update_animations(before_change_style, tasks) };
}
}
}
Expand All @@ -326,14 +324,14 @@ impl<E: TElement> SequentialTask<E> {
/// a given (pseudo-)element.
#[cfg(feature = "gecko")]
pub fn update_animations(el: E,
pseudo: Option<PseudoElement>,
before_change_style: Option<Arc<ComputedValues>>,
tasks: UpdateAnimationsTasks) -> Self {
use self::SequentialTask::*;
UpdateAnimations { el: unsafe { SendElement::new(el) },
pseudo: pseudo,
before_change_style: before_change_style,
tasks: tasks }
UpdateAnimations {
el: unsafe { SendElement::new(el) },
before_change_style: before_change_style,
tasks: tasks,
}
}
}

Expand Down
15 changes: 15 additions & 0 deletions components/style/data.rs
Expand Up @@ -532,6 +532,21 @@ impl ElementData {
self.styles = Some(styles);
}

/// Sets the computed element rules, and returns whether the rules changed.
pub fn set_primary_rules(&mut self, rules: StrongRuleNode) -> bool {
if !self.has_styles() {
self.set_styles(ElementStyles::new(ComputedStyle::new_partial(rules)));
return true;
}

if self.styles().primary.rules == rules {
return false;
}

self.styles_mut().primary.rules = rules;
true
}

/// Returns true if the Element has a RestyleData.
pub fn has_restyle(&self) -> bool {
self.restyle.is_some()
Expand Down
57 changes: 38 additions & 19 deletions components/style/dom.rs
Expand Up @@ -274,11 +274,20 @@ pub trait PresentationalHintsSynthetizer {
where V: Push<ApplicableDeclarationBlock>;
}

/// The animation rules. The first one is for Animation cascade level, and the second one is for
/// The animation rules.
///
/// The first one is for Animation cascade level, and the second one is for
/// Transition cascade level.
pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
pub Option<Arc<Locked<PropertyDeclarationBlock>>>);

impl AnimationRules {
/// Returns whether these animation rules represents an actual rule or not.
pub fn is_empty(&self) -> bool {
self.0.is_none() && self.1.is_none()
}
}

/// The element trait, the main abstraction the style crate acts over.
pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
ElementExt + PresentationalHintsSynthetizer {
Expand Down Expand Up @@ -325,26 +334,25 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
}

/// Get this element's animation rules.
fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules {
fn get_animation_rules(&self) -> AnimationRules {
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.
fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
fn get_animation_rule(&self)
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
None
}

/// Get this element's transition rule.
fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>)
fn get_transition_rule(&self)
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
None
}
Expand Down Expand Up @@ -428,6 +436,18 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
/// anonymous content).
fn is_native_anonymous(&self) -> bool { false }

/// Returns the pseudo-element implemented by this element, if any.
///
/// Gecko traverses pseudo-elements during the style traversal, and we need
/// to know this so we can properly grab the pseudo-element style from the
/// parent element.
///
/// Note that we still need to compute the pseudo-elements before-hand,
/// given otherwise we don't know if we need to create an element or not.
///
/// Servo doesn't have to deal with this.
fn implemented_pseudo_element(&self) -> Option<PseudoElement> { None }

/// Atomically stores the number of children of this node that we will
/// need to process during bottom-up traversal.
fn store_children_to_process(&self, n: isize);
Expand Down Expand Up @@ -469,21 +489,21 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +

/// Creates a task to update various animation state on a given (pseudo-)element.
#[cfg(feature = "gecko")]
fn update_animations(&self, _pseudo: Option<&PseudoElement>,
fn update_animations(&self,
before_change_style: Option<Arc<ComputedValues>>,
tasks: UpdateAnimationsTasks);

/// Returns true if the element has relevant animations. Relevant
/// animations are those animations that are affecting the element's style
/// or are scheduled to do so in the future.
fn has_animations(&self, _pseudo: Option<&PseudoElement>) -> bool;
fn has_animations(&self) -> bool;

/// Returns true if the element has a CSS animation.
fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool;
fn has_css_animations(&self) -> bool;

/// Returns true if the element has a CSS transition (including running transitions and
/// completed transitions).
fn has_css_transitions(&self, _pseudo: Option<&PseudoElement>) -> bool;
fn has_css_transitions(&self) -> bool;

/// Returns true if the element has animation restyle hints.
fn has_animation_restyle_hints(&self) -> bool {
Expand All @@ -497,8 +517,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +

/// Gets the current existing CSS transitions, by |property, end value| pairs in a HashMap.
#[cfg(feature = "gecko")]
fn get_css_transitions_info(&self,
pseudo: Option<&PseudoElement>)
fn get_css_transitions_info(&self)
-> HashMap<TransitionProperty, Arc<AnimationValue>>;

/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
Expand All @@ -508,27 +527,27 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
/// reduce the possibility of false positives.
#[cfg(feature = "gecko")]
fn might_need_transitions_update(&self,
old_values: &Option<&Arc<ComputedValues>>,
new_values: &Arc<ComputedValues>,
pseudo: Option<&PseudoElement>) -> bool;
old_values: Option<&ComputedValues>,
new_values: &ComputedValues)
-> bool;

/// Returns true if one of the transitions needs to be updated on this element. We check all
/// the transition properties to make sure that updating transitions is necessary.
/// This method should only be called if might_needs_transitions_update returns true when
/// passed the same parameters.
#[cfg(feature = "gecko")]
fn needs_transitions_update(&self,
before_change_style: &Arc<ComputedValues>,
after_change_style: &Arc<ComputedValues>,
pseudo: Option<&PseudoElement>) -> bool;
before_change_style: &ComputedValues,
after_change_style: &ComputedValues)
-> bool;

/// Returns true if we need to update transitions for the specified property on this element.
#[cfg(feature = "gecko")]
fn needs_transitions_update_per_property(&self,
property: &TransitionProperty,
combined_duration: f32,
before_change_style: &Arc<ComputedValues>,
after_change_style: &Arc<ComputedValues>,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
existing_transitions: &HashMap<TransitionProperty,
Arc<AnimationValue>>)
-> bool;
Expand Down
39 changes: 22 additions & 17 deletions components/style/gecko/selector_parser.rs
Expand Up @@ -54,6 +54,26 @@ pub const EAGER_PSEUDO_COUNT: usize = 2;


impl PseudoElement {
/// Returns the kind of cascade type that a given pseudo is going to use.
///
/// In Gecko we only compute ::before and ::after eagerly. We save the rules
/// for anonymous boxes separately, so we resolve them as precomputed
/// pseudos.
///
/// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
pub fn cascade_type(&self) -> PseudoElementCascadeType {
if self.is_eager() {
debug_assert!(!self.is_anon_box());
return PseudoElementCascadeType::Eager
}

if self.is_anon_box() {
return PseudoElementCascadeType::Precomputed
}

PseudoElementCascadeType::Lazy
}

/// Gets the canonical index of this eagerly-cascaded pseudo-element.
#[inline]
pub fn eager_index(&self) -> usize {
Expand Down Expand Up @@ -437,24 +457,9 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {

impl SelectorImpl {
#[inline]
/// Returns the kind of cascade type that a given pseudo is going to use.
///
/// In Gecko we only compute ::before and ::after eagerly. We save the rules
/// for anonymous boxes separately, so we resolve them as precomputed
/// pseudos.
///
/// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
/// Legacy alias for PseudoElement::cascade_type.
pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
if pseudo.is_eager() {
debug_assert!(!pseudo.is_anon_box());
return PseudoElementCascadeType::Eager
}

if pseudo.is_anon_box() {
return PseudoElementCascadeType::Precomputed
}

PseudoElementCascadeType::Lazy
pseudo.cascade_type()
}

/// A helper to traverse each eagerly cascaded pseudo-element, executing
Expand Down

0 comments on commit be0139f

Please sign in to comment.