auto merge of #1297 : SimonSapin/servo/last-child, r=SimonSapin

Same as #1296, with a fixed commit message.
This commit is contained in:
bors-servo 2013-11-21 08:58:10 -08:00
commit df7ec2613b
7 changed files with 132 additions and 2 deletions

View file

@ -478,6 +478,10 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
} }
FirstChild => matches_first_child(element), FirstChild => matches_first_child(element),
LastChild => matches_last_child(element),
OnlyChild => matches_first_child(element) && matches_last_child(element),
Root => matches_root(element), Root => matches_root(element),
Negation(ref negated) => { Negation(ref negated) => {
@ -525,6 +529,29 @@ fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Element
} }
} }
#[inline]
fn matches_last_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, 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] #[inline]
fn match_attribute<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>( fn match_attribute<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool { attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool {

View file

@ -62,7 +62,7 @@ pub enum SimpleSelector {
AnyLink, AnyLink,
Link, Link,
Visited, Visited,
FirstChild, FirstChild, LastChild, OnlyChild,
// Empty, // Empty,
Root, Root,
// Lang(~str), // Lang(~str),
@ -191,7 +191,7 @@ fn compute_specificity(mut selector: &CompoundSelector,
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*) | &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*) | &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
| &AnyLink | &Link | &Visited | &AnyLink | &Link | &Visited
| &FirstChild | &Root | &FirstChild | &LastChild | &OnlyChild | &Root
// | &Empty | &Lang(*) | &NthChild(*) // | &Empty | &Lang(*) | &NthChild(*)
=> specificity.class_like_selectors += 1, => specificity.class_like_selectors += 1,
&NamespaceSelector(*) => (), &NamespaceSelector(*) => (),
@ -438,6 +438,8 @@ fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
"link" => Some(Link), "link" => Some(Link),
"visited" => Some(Visited), "visited" => Some(Visited),
"first-child" => Some(FirstChild), "first-child" => Some(FirstChild),
"last-child" => Some(LastChild),
"only-child" => Some(OnlyChild),
"root" => Some(Root), "root" => Some(Root),
// "empty" => Some(Empty), // "empty" => Some(Empty),
_ => None _ => None

View file

@ -3,3 +3,5 @@
== margin_a.html margin_b.html == margin_a.html margin_b.html
== root_pseudo_a.html root_pseudo_b.html == root_pseudo_a.html root_pseudo_b.html
== first_child_pseudo_a.html first_child_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

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>:last-child test</title>
<style type="text/css">
html:last-child { background: red; }
html { background: yellow;}
p { width: 20px; height: 20px; background: orange; float: left; margin-left: 10px; }
div { clear: both; }
#p1, #p2, #p3 { background: red; }
#d1 > *:last-child { background: green }
#d2 > *:last-child { background: green }
#d3 > *:last-child { background: green }
#p4 { background: green; }
#d4 > *:last-child { background: red }
</style>
</head>
<body>
<div id="d1"><p> </p><p id="p1"> </p></div>
<div id="d2"><p> </p><p id="p2"> </p> </div>
<div id="d3"><p> </p><p id="p3"> </p><!-- comment --></div>
<div id="d4"><p> </p><p id="p4"> </p><span> </span></div>
</body>
</html>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>:last-child test</title>
<style type="text/css">
html { background: yellow;}
p { width: 20px; height: 20px; background: orange; float: left; margin-left: 10px; }
div { clear: both; }
#p1 { background: green; }
#p2 { background: green; }
#p3 { background: green; }
#p4 { background: green; }
</style>
</head>
<body>
<div id="d1"><p> </p><p id="p1"> </p></div>
<div id="d2"><p> </p><p id="p2"> </p> </div>
<div id="d3"><p> </p><p id="p3"> </p><!-- comment --></div>
<div id="d4"><p> </p><p id="p4"> </p><span> </span></div>
</body>
</html>

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>:only-child test</title>
<style type="text/css">
html:only-child { background: red; }
html { background: yellow;}
p { width: 20px; height: 20px; background: orange; float: left; margin-left: 10px; }
div { clear: both; }
#d1 > p, #d2 > p, #d3 > p, #d4 > p { background: red; }
#d1 > *:only-child { background: green }
#d2 > *:only-child { background: green }
#d3 > *:only-child { background: green }
#d4 > *:only-child { background: green }
#p5, #p6 { background: green; }
#d5 > *:only-child { background: red }
#d6 > *:only-child { background: red }
</style>
</head>
<body>
<div id="d1"><p> </p></div>
<div id="d2"> <p> </p></div>
<div id="d3"><p> </p><!-- comment --></div>
<div id="d4"><!-- comment --><p> </p></div>
<div id="d5"><p id="p5"> </p><span> </span></div>
<div id="d6"><span> </span><p id="p6"> </p></div>
</body>
</html>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>:only-child test</title>
<style type="text/css">
html:only-child { background: red; }
html { background: yellow;}
p { width: 20px; height: 20px; background: orange; float: left; margin-left: 10px; }
div { clear: both; }
#d1 > p, #d2 > p, #d3 > p, #d4 > p { background: green; }
#p5, #p6 { background: green; }
</style>
</head>
<body>
<div id="d1"><p> </p></div>
<div id="d2"> <p> </p></div>
<div id="d3"><p> </p><!-- comment --></div>
<div id="d4"><!-- comment --><p> </p></div>
<div id="d5"><p id="p5"> </p><span> </span></div>
<div id="d6"><span> </span><p id="p6"> </p></div>
</body>
</html>