Skip to content

Commit

Permalink
Implement :root pseudo-class. Fix #1263, fix #1265
Browse files Browse the repository at this point in the history
  • Loading branch information
therealglazou authored and SimonSapin committed Nov 20, 2013
1 parent 45c0d0e commit 9b69161
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 20 deletions.
19 changes: 5 additions & 14 deletions src/components/script/dom/node.rs
Expand Up @@ -242,8 +242,11 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
}
}

fn is_root(&self) -> bool {
self.parent_node().is_none()
fn is_document(&self) -> bool {
match self.type_id() {
DocumentNodeTypeId(*) => true,
_ => false
}
}
}

Expand Down Expand Up @@ -327,11 +330,6 @@ impl<'self, View> AbstractNode<View> {
self.node().next_sibling
}

/// Is this node a root?
pub fn is_root(self) -> bool {
self.parent_node().is_none()
}

//
// Downcasting borrows
//
Expand Down Expand Up @@ -434,13 +432,6 @@ impl<'self, View> AbstractNode<View> {
self.transmute_mut(f)
}

pub fn is_document(self) -> bool {
match self.type_id() {
DocumentNodeTypeId(*) => true,
_ => false
}
}

// FIXME: This should be doing dynamic borrow checking for safety.
pub fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
if !self.is_element() {
Expand Down
19 changes: 18 additions & 1 deletion src/components/style/selector_matching.rs
Expand Up @@ -478,6 +478,8 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
}
FirstChild => matches_first_child(element),

Root => matches_root(element),

Negation(ref negated) => {
!negated.iter().all(|s| matches_simple_selector(s, element))
},
Expand All @@ -491,6 +493,15 @@ fn url_is_visited(_url: &str) -> bool {
false
}

#[inline]
fn matches_root<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
element: &T) -> bool {
match element.node().parent_node() {
Some(parent) => parent.is_document(),
None => false
}
}

#[inline]
fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
element: &T) -> bool {
Expand All @@ -502,8 +513,14 @@ fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Element
if node.is_element() {
return false
}
},
None => match node.node().parent_node() {
// Selectors level 3 says :first-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
}
None => return !element.is_root(),
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions src/components/style/selectors.rs
Expand Up @@ -64,7 +64,7 @@ pub enum SimpleSelector {
Visited,
FirstChild,
// Empty,
// Root,
Root,
// Lang(~str),
// NthChild(i32, i32),
// ...
Expand Down Expand Up @@ -190,8 +190,9 @@ fn compute_specificity(mut selector: &CompoundSelector,
&ClassSelector(*)
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
| &AnyLink | &Link | &Visited | &FirstChild
// | &Empty | &Root | &Lang(*) | &NthChild(*)
| &AnyLink | &Link | &Visited
| &FirstChild | &Root
// | &Empty | &Lang(*) | &NthChild(*)
=> specificity.class_like_selectors += 1,
&NamespaceSelector(*) => (),
&Negation(ref negated)
Expand Down Expand Up @@ -437,7 +438,7 @@ fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
"link" => Some(Link),
"visited" => Some(Visited),
"first-child" => Some(FirstChild),
// "root" => Some(Root),
"root" => Some(Root),
// "empty" => Some(Empty),
_ => None
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/util/tree.rs
Expand Up @@ -263,7 +263,7 @@ pub trait TreeNodeRef<Node>: Clone {

fn is_element(&self) -> bool;

fn is_root(&self) -> bool;
fn is_document(&self) -> bool;
}

pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> {
Expand Down
17 changes: 17 additions & 0 deletions src/test/html/test-css-pseudo-root.html
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
<link rel="author" title="Daniel Glazman" href="mailto:d.glazman@partner.samsung.com" />
<title>:root test</title>
<style type="text/css">
html:root { background: green; }
html { background: red; }
p:root { background: red; }
</style>
</head>
<body>
The background of the page should be green and you should see not red at all.
<p>And the background of this sentence should be green too.</p>
</body>
</html>
2 changes: 2 additions & 0 deletions src/test/ref/basic.list
@@ -1,3 +1,5 @@
== basic_width_px.html basic_width_em.html
== hello_a.html hello_b.html
== margin_a.html margin_b.html
== root_pseudo_a.html root_pseudo_b.html
== first_child_pseudo_a.html first_child_pseudo_b.html
25 changes: 25 additions & 0 deletions src/test/ref/first_child_pseudo_a.html
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>:first-child test</title>
<style type="text/css">
html:first-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 > *:first-child { background: green }
#d2 > *:first-child { background: green }
#d3 > *:first-child { background: green }
#p4 { background: green; }
#d4 > *:first-child { background: red }
</style>
</head>
<body>
<div id="d1"><p id="p1"> </p><p> </p></div>
<div id="d2"> <p id="p2"> </p><p> </p></div>
<div id="d3"><!-- comment --><p id="p3"> </p><p> </p></div>
<div id="d4"><span> </span><p id="p4"> </p><p> </p></div>
</body>
</html>
22 changes: 22 additions & 0 deletions src/test/ref/first_child_pseudo_b.html
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>:first-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 id="p1"> </p><p> </p></div>
<div id="d2"> <p id="p2"> </p><p> </p></div>
<div id="d3"><!-- comment --><p id="p3"> </p><p> </p></div>
<div id="d4"><span> </span><p id="p4"> </p><p> </p></div>
</body>
</html>
15 changes: 15 additions & 0 deletions src/test/ref/root_pseudo_a.html
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>:root test</title>
<style type="text/css">
html:root { background: green; }
html { background: red; }
p:root { background: red; }
</style>
</head>
<body>
The background of the page should be green and you should see not red at all.
<p>And the background of this sentence should be green too.</p>
</body>
</html>
13 changes: 13 additions & 0 deletions src/test/ref/root_pseudo_b.html
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>:root test</title>
<style type="text/css">
html { background: green; }
</style>
</head>
<body>
The background of the page should be green and you should see not red at all.
<p>And the background of this sentence should be green too.</p>
</body>
</html>

5 comments on commit 9b69161

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from SimonSapin
at SimonSapin@9b69161

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging SimonSapin/servo/root = 9b69161 into auto

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SimonSapin/servo/root = 9b69161 merged ok, testing candidate = eabee53

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = eabee53

Please sign in to comment.