diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs index 723119fdeae1..3585bb16b646 100644 --- a/src/components/style/selector_matching.rs +++ b/src/components/style/selector_matching.rs @@ -478,6 +478,10 @@ fn matches_simple_selector, T: TreeNodeRefAsElement, E: Ele } FirstChild => matches_first_child(element), + LastChild => matches_last_child(element), + + OnlyChild => matches_first_child(element) && matches_last_child(element), + Root => matches_root(element), Negation(ref negated) => { @@ -525,6 +529,29 @@ fn matches_first_child, T: TreeNodeRefAsElement, E: Element } } +#[inline] +fn matches_last_child, T: TreeNodeRefAsElement, E: ElementLike>( + element: &T) -> bool { + let mut node = element.clone(); + loop { + match node.node().next_sibling() { + Some(next_sibling) => { + node = next_sibling; + if node.is_element() { + return false + } + }, + None => match node.node().parent_node() { + // Selectors level 3 says :last-child does not match the + // root of the document; Warning, level 4 says, for the time + // being, the contrary... + Some(parent) => return !parent.is_document(), + None => return false + } + } + } +} + #[inline] fn match_attribute, T: TreeNodeRefAsElement, E: ElementLike>( attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool { diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs index aa7bdb03bca5..d668b8085a4a 100644 --- a/src/components/style/selectors.rs +++ b/src/components/style/selectors.rs @@ -62,7 +62,7 @@ pub enum SimpleSelector { AnyLink, Link, Visited, - FirstChild, + FirstChild, LastChild, OnlyChild, // Empty, Root, // Lang(~str), @@ -191,7 +191,7 @@ fn compute_specificity(mut selector: &CompoundSelector, | &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*) | &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*) | &AnyLink | &Link | &Visited - | &FirstChild | &Root + | &FirstChild | &LastChild | &OnlyChild | &Root // | &Empty | &Lang(*) | &NthChild(*) => specificity.class_like_selectors += 1, &NamespaceSelector(*) => (), @@ -438,6 +438,8 @@ fn parse_simple_pseudo_class(name: &str) -> Option { "link" => Some(Link), "visited" => Some(Visited), "first-child" => Some(FirstChild), + "last-child" => Some(LastChild), + "only-child" => Some(OnlyChild), "root" => Some(Root), // "empty" => Some(Empty), _ => None diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list index 778c344d0e34..649d35a28ca4 100644 --- a/src/test/ref/basic.list +++ b/src/test/ref/basic.list @@ -3,3 +3,5 @@ == margin_a.html margin_b.html == root_pseudo_a.html root_pseudo_b.html == first_child_pseudo_a.html first_child_pseudo_b.html +== last_child_pseudo_a.html last_child_pseudo_b.html +== only_child_pseudo_a.html only_child_pseudo_b.html diff --git a/src/test/ref/last_child_pseudo_a.html b/src/test/ref/last_child_pseudo_a.html new file mode 100644 index 000000000000..73f48120e0c1 --- /dev/null +++ b/src/test/ref/last_child_pseudo_a.html @@ -0,0 +1,25 @@ + + + + :last-child test + + + +

+

+

+

+ + diff --git a/src/test/ref/last_child_pseudo_b.html b/src/test/ref/last_child_pseudo_b.html new file mode 100644 index 000000000000..eb6ef645c7b3 --- /dev/null +++ b/src/test/ref/last_child_pseudo_b.html @@ -0,0 +1,22 @@ + + + + :last-child test + + + +

+

+

+

+ + diff --git a/src/test/ref/only_child_pseudo_a.html b/src/test/ref/only_child_pseudo_a.html new file mode 100644 index 000000000000..8eaf71f3fedb --- /dev/null +++ b/src/test/ref/only_child_pseudo_a.html @@ -0,0 +1,29 @@ + + + + :only-child test + + + +

+

+

+

+

+

+ + diff --git a/src/test/ref/only_child_pseudo_b.html b/src/test/ref/only_child_pseudo_b.html new file mode 100644 index 000000000000..7723dd549ceb --- /dev/null +++ b/src/test/ref/only_child_pseudo_b.html @@ -0,0 +1,23 @@ + + + + :only-child test + + + +

+

+

+

+

+

+ +