mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Process animation-only traversal.
All traversal processes are like this: 1. Traverse only elements that have this restyle hint (animation-only traversal) RESTYLE_CSS_ANIMATIONS is stripped off from restyle hints of the elements 2. Traverse all dirty elements (normal traversal) 3. Create a SequentialTask if we have updated CSS Animations properties in the normal traversal 4. Traverse elements that need to have updated animation style as a result of 3 (second animation-only traversal)
This commit is contained in:
parent
be332fe5a4
commit
e4fe416c9d
2 changed files with 48 additions and 8 deletions
|
@ -134,6 +134,8 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
/// The traversal_flag is used in Gecko.
|
||||
/// If traversal_flag::UNSTYLED_CHILDREN_ONLY is specified, style newly-
|
||||
/// appended children without restyling the parent.
|
||||
/// If traversal_flag::ANIMATION_ONLY is specified, style only elements for
|
||||
/// animations.
|
||||
fn pre_traverse(root: E, stylist: &Stylist, traversal_flags: TraversalFlags)
|
||||
-> PreTraverseToken
|
||||
{
|
||||
|
@ -158,7 +160,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
PreTraverseToken {
|
||||
traverse: Self::node_needs_traversal(root.as_node()),
|
||||
traverse: Self::node_needs_traversal(root.as_node(), traversal_flags.for_animation_only()),
|
||||
unstyled_children_only: false,
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +174,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
/// Returns true if traversal is needed for the given node and subtree.
|
||||
fn node_needs_traversal(node: E::ConcreteNode) -> bool {
|
||||
fn node_needs_traversal(node: E::ConcreteNode, animation_only: bool) -> bool {
|
||||
// Non-incremental layout visits every node.
|
||||
if cfg!(feature = "servo") && opts::get().nonincremental_layout {
|
||||
return true;
|
||||
|
@ -181,6 +183,22 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
match node.as_element() {
|
||||
None => Self::text_node_needs_traversal(node),
|
||||
Some(el) => {
|
||||
// In case of animation-only traversal we need to traverse
|
||||
// the element if the element has animation only dirty
|
||||
// descendants bit, animation-only restyle hint or recascade.
|
||||
if animation_only {
|
||||
if el.has_animation_only_dirty_descendants() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let data = match el.borrow_data() {
|
||||
Some(d) => d,
|
||||
None => return false,
|
||||
};
|
||||
return data.get_restyle()
|
||||
.map_or(false, |r| r.hint.has_animation_hint() || r.recascade);
|
||||
}
|
||||
|
||||
// If the dirty descendants bit is set, we need to traverse no
|
||||
// matter what. Skip examining the ElementData.
|
||||
if el.has_dirty_descendants() {
|
||||
|
@ -293,7 +311,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
for kid in parent.as_node().children() {
|
||||
if Self::node_needs_traversal(kid) {
|
||||
if Self::node_needs_traversal(kid, self.shared_context().animation_only_restyle) {
|
||||
let el = kid.as_element();
|
||||
if el.as_ref().and_then(|el| el.borrow_data())
|
||||
.map_or(false, |d| d.has_styles())
|
||||
|
@ -471,21 +489,38 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
|||
None => empty_hint,
|
||||
Some(r) => {
|
||||
r.recascade = false;
|
||||
mem::replace(&mut r.hint, empty_hint).propagate()
|
||||
if r.hint.has_animation_hint() {
|
||||
debug_assert!(context.shared.animation_only_restyle,
|
||||
"animation restyle hint should be handled during animation-only restyles");
|
||||
// Drop animation restyle hint.
|
||||
let propagated_hint = r.hint.propagate();
|
||||
r.hint.remove_animation_hint();
|
||||
propagated_hint
|
||||
} else {
|
||||
mem::replace(&mut r.hint, empty_hint).propagate()
|
||||
}
|
||||
},
|
||||
};
|
||||
debug_assert!(data.has_current_styles());
|
||||
debug_assert!(data.has_current_styles() || context.shared.animation_only_restyle,
|
||||
"Should have computed style or haven't yet valid computed style in case of animation-only restyle");
|
||||
trace!("propagated_hint={:?}, inherited_style_changed={:?}", propagated_hint, inherited_style_changed);
|
||||
|
||||
// Preprocess children, propagating restyle hints and handling sibling relationships.
|
||||
if traversal.should_traverse_children(&mut context.thread_local, element, &data, DontLog) &&
|
||||
(element.has_dirty_descendants() || !propagated_hint.is_empty() || inherited_style_changed) {
|
||||
((!context.shared.animation_only_restyle && element.has_dirty_descendants()) ||
|
||||
(context.shared.animation_only_restyle && element.has_animation_only_dirty_descendants()) ||
|
||||
!propagated_hint.is_empty() ||
|
||||
inherited_style_changed) {
|
||||
let damage_handled = data.get_restyle().map_or(RestyleDamage::empty(), |r| {
|
||||
r.damage_handled() | r.damage.handled_for_descendants()
|
||||
});
|
||||
preprocess_children(traversal, element, propagated_hint, damage_handled, inherited_style_changed);
|
||||
}
|
||||
|
||||
if context.shared.animation_only_restyle {
|
||||
unsafe { element.unset_animation_only_dirty_descendants(); }
|
||||
}
|
||||
|
||||
// Make sure the dirty descendants bit is not set for the root of a
|
||||
// display:none subtree, even if the style didn't change (since, if
|
||||
// the style did change, we'd have already cleared it above).
|
||||
|
|
|
@ -83,8 +83,8 @@ use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
|
|||
use style::supports::parse_condition_or_declaration;
|
||||
use style::thread_state;
|
||||
use style::timer::Timer;
|
||||
use style::traversal::{ANIMATION_ONLY, UNSTYLED_CHILDREN_ONLY};
|
||||
use style::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags};
|
||||
use style::traversal::UNSTYLED_CHILDREN_ONLY;
|
||||
use style_traits::ToCss;
|
||||
use super::stylesheet_loader::StylesheetLoader;
|
||||
|
||||
|
@ -202,6 +202,11 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
|||
_ => TraversalFlags::empty(),
|
||||
};
|
||||
|
||||
if element.has_animation_only_dirty_descendants() ||
|
||||
element.has_animation_restyle_hints() {
|
||||
traverse_subtree(element, raw_data, traversal_flags | ANIMATION_ONLY);
|
||||
}
|
||||
|
||||
traverse_subtree(element, raw_data, traversal_flags);
|
||||
|
||||
element.has_dirty_descendants() || element.mutate_data().unwrap().has_restyle()
|
||||
|
@ -1612,7 +1617,7 @@ pub extern "C" fn Servo_AssertTreeIsClean(root: RawGeckoElementBorrowed) {
|
|||
|
||||
let root = GeckoElement(root);
|
||||
fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
|
||||
debug_assert!(!el.has_dirty_descendants());
|
||||
debug_assert!(!el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants());
|
||||
for child in el.as_node().children() {
|
||||
if let Some(child) = child.as_element() {
|
||||
assert_subtree_is_clean(child);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue