diff options
author | Matt Brubeck <mbrubeck@limpet.net> | 2016-02-19 17:05:38 -0800 |
---|---|---|
committer | Matt Brubeck <mbrubeck@limpet.net> | 2016-02-23 17:31:38 -0800 |
commit | 973918967f606d723fb7b71e14d682b16fa50e9d (patch) | |
tree | 2e55d0c12fd1313fb1904880c7441ea52acab17c /components/script/dom/node.rs | |
parent | d85ee09bc72a9819269455a126a1eda018254822 (diff) | |
download | servo-973918967f606d723fb7b71e14d682b16fa50e9d.tar.gz servo-973918967f606d723fb7b71e14d682b16fa50e9d.zip |
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
Diffstat (limited to 'components/script/dom/node.rs')
-rw-r--r-- | components/script/dom/node.rs | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index c2221408b13..f1ebf6f9965 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -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 |