Implement :root pseudo-class. Fix #1263, fix #1265

This commit is contained in:
Daniel Glazman 2013-11-15 14:52:52 +01:00 committed by Simon Sapin
parent 45c0d0e17d
commit 9b691611ff
10 changed files with 123 additions and 20 deletions

View file

@ -242,8 +242,11 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
} }
} }
fn is_root(&self) -> bool { fn is_document(&self) -> bool {
self.parent_node().is_none() match self.type_id() {
DocumentNodeTypeId(*) => true,
_ => false
}
} }
} }
@ -327,11 +330,6 @@ impl<'self, View> AbstractNode<View> {
self.node().next_sibling self.node().next_sibling
} }
/// Is this node a root?
pub fn is_root(self) -> bool {
self.parent_node().is_none()
}
// //
// Downcasting borrows // Downcasting borrows
// //
@ -434,13 +432,6 @@ impl<'self, View> AbstractNode<View> {
self.transmute_mut(f) 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. // FIXME: This should be doing dynamic borrow checking for safety.
pub fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R { pub fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
if !self.is_element() { if !self.is_element() {

View file

@ -478,6 +478,8 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
} }
FirstChild => matches_first_child(element), FirstChild => matches_first_child(element),
Root => matches_root(element),
Negation(ref negated) => { Negation(ref negated) => {
!negated.iter().all(|s| matches_simple_selector(s, element)) !negated.iter().all(|s| matches_simple_selector(s, element))
}, },
@ -491,6 +493,15 @@ fn url_is_visited(_url: &str) -> bool {
false 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] #[inline]
fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>( fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
element: &T) -> bool { element: &T) -> bool {
@ -502,8 +513,14 @@ fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Element
if node.is_element() { if node.is_element() {
return false 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(),
} }
} }
} }

View file

@ -64,7 +64,7 @@ pub enum SimpleSelector {
Visited, Visited,
FirstChild, FirstChild,
// Empty, // Empty,
// Root, Root,
// Lang(~str), // Lang(~str),
// NthChild(i32, i32), // NthChild(i32, i32),
// ... // ...
@ -190,8 +190,9 @@ fn compute_specificity(mut selector: &CompoundSelector,
&ClassSelector(*) &ClassSelector(*)
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*) | &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*) | &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
| &AnyLink | &Link | &Visited | &FirstChild | &AnyLink | &Link | &Visited
// | &Empty | &Root | &Lang(*) | &NthChild(*) | &FirstChild | &Root
// | &Empty | &Lang(*) | &NthChild(*)
=> specificity.class_like_selectors += 1, => specificity.class_like_selectors += 1,
&NamespaceSelector(*) => (), &NamespaceSelector(*) => (),
&Negation(ref negated) &Negation(ref negated)
@ -437,7 +438,7 @@ 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),
// "root" => Some(Root), "root" => Some(Root),
// "empty" => Some(Empty), // "empty" => Some(Empty),
_ => None _ => None
} }

View file

@ -263,7 +263,7 @@ pub trait TreeNodeRef<Node>: Clone {
fn is_element(&self) -> bool; fn is_element(&self) -> bool;
fn is_root(&self) -> bool; fn is_document(&self) -> bool;
} }
pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> { pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> {

View file

@ -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>

View file

@ -1,3 +1,5 @@
== basic_width_px.html basic_width_em.html == basic_width_px.html basic_width_em.html
== hello_a.html hello_b.html == hello_a.html hello_b.html
== margin_a.html margin_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

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>