mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Dirty elements whose selectors are affected by sibling changes
This fixes incremental layout of nodes that match pseudo-class selectors such as :first-child, :nth-child, :last-child, :first-of-type, etc. * Fixes #8191 * Fixes #9063 * Fixes #9303 * Fixes #9448 This code is based on the following flags from Gecko: https://hg.mozilla.org/mozilla-central/file/e1cf617a1f28/dom/base/nsINode.h#l134
This commit is contained in:
parent
d85ee09bc7
commit
973918967f
14 changed files with 145 additions and 47 deletions
|
@ -2399,6 +2399,54 @@ impl<'a> ChildrenMutation<'a> {
|
|||
-> ChildrenMutation<'a> {
|
||||
ChildrenMutation::ReplaceAll { removed: removed, added: added }
|
||||
}
|
||||
|
||||
/// Get the child that follows the added or removed children.
|
||||
pub fn next_child(&self) -> Option<&Node> {
|
||||
match *self {
|
||||
ChildrenMutation::Append { .. } => None,
|
||||
ChildrenMutation::Insert { next, .. } => Some(next),
|
||||
ChildrenMutation::Prepend { next, .. } => Some(next),
|
||||
ChildrenMutation::Replace { next, .. } => next,
|
||||
ChildrenMutation::ReplaceAll { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// If nodes were added or removed at the start or end of a container, return any
|
||||
/// previously-existing child whose ":first-child" or ":last-child" status *may* have changed.
|
||||
///
|
||||
/// NOTE: This does not check whether the inserted/removed nodes were elements, so in some
|
||||
/// cases it will return a false positive. This doesn't matter for correctness, because at
|
||||
/// worst the returned element will be restyled unnecessarily.
|
||||
pub fn modified_edge_element(&self) -> Option<Root<Node>> {
|
||||
match *self {
|
||||
// Add/remove at start of container: Return the first following element.
|
||||
ChildrenMutation::Prepend { next, .. } |
|
||||
ChildrenMutation::Replace { prev: None, next: Some(next), .. } => {
|
||||
next.inclusively_following_siblings().filter(|node| node.is::<Element>()).next()
|
||||
}
|
||||
// Add/remove at end of container: Return the last preceding element.
|
||||
ChildrenMutation::Append { prev, .. } |
|
||||
ChildrenMutation::Replace { prev: Some(prev), next: None, .. } => {
|
||||
prev.inclusively_preceding_siblings().filter(|node| node.is::<Element>()).next()
|
||||
}
|
||||
// Insert or replace in the middle:
|
||||
ChildrenMutation::Insert { prev, next, .. } |
|
||||
ChildrenMutation::Replace { prev: Some(prev), next: Some(next), .. } => {
|
||||
if prev.inclusively_preceding_siblings().all(|node| !node.is::<Element>()) {
|
||||
// Before the first element: Return the first following element.
|
||||
next.inclusively_following_siblings().filter(|node| node.is::<Element>()).next()
|
||||
} else if next.inclusively_following_siblings().all(|node| !node.is::<Element>()) {
|
||||
// After the last element: Return the last preceding element.
|
||||
prev.inclusively_preceding_siblings().filter(|node| node.is::<Element>()).next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
ChildrenMutation::Replace { prev: None, next: None, .. } => unreachable!(),
|
||||
ChildrenMutation::ReplaceAll { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The context of the unbinding from a tree of a node when one of its
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue