aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/node.rs
diff options
context:
space:
mode:
authorMatt Brubeck <mbrubeck@limpet.net>2016-02-19 17:05:38 -0800
committerMatt Brubeck <mbrubeck@limpet.net>2016-02-23 17:31:38 -0800
commit973918967f606d723fb7b71e14d682b16fa50e9d (patch)
tree2e55d0c12fd1313fb1904880c7441ea52acab17c /components/script/dom/node.rs
parentd85ee09bc72a9819269455a126a1eda018254822 (diff)
downloadservo-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.rs48
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