Skip to content

Commit

Permalink
Implementation of pseudo class 'first-child'.
Browse files Browse the repository at this point in the history
  • Loading branch information
parkjaeman authored and SimonSapin committed Oct 29, 2013
1 parent 572ba98 commit 6dba191
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 24 deletions.
8 changes: 6 additions & 2 deletions src/components/script/dom/node.rs
Expand Up @@ -164,6 +164,10 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
_ => false
}
}

fn is_root(&self) -> bool {
self.parent_node().is_none()
}
}

impl<View> TreeNodeRefAsElement<Node<View>, Element> for AbstractNode<View> {
Expand Down Expand Up @@ -611,7 +615,7 @@ impl Node<ScriptView> {
}

pub fn GetPreviousSibling(&self) -> Option<AbstractNode<ScriptView>> {
self.prev_sibling
self.prev_sibling
}

pub fn GetNextSibling(&self) -> Option<AbstractNode<ScriptView>> {
Expand All @@ -621,7 +625,7 @@ impl Node<ScriptView> {
pub fn GetNodeValue(&self, abstract_self: AbstractNode<ScriptView>) -> DOMString {
match self.type_id {
// ProcessingInstruction
CommentNodeTypeId | TextNodeTypeId => {
CommentNodeTypeId | TextNodeTypeId => {
do abstract_self.with_imm_characterdata() |characterdata| {
characterdata.Data()
}
Expand Down
70 changes: 50 additions & 20 deletions src/components/style/selector_matching.rs
Expand Up @@ -150,13 +150,10 @@ fn matches_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLik
matches_compound_selector::<N, T, E>(&selector.compound_selectors, element)
}


fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
selector: &CompoundSelector, element: &T) -> bool {
if do element.with_imm_element_like |element: &E| {
!do selector.simple_selectors.iter().all |simple_selector| {
if !do selector.simple_selectors.iter().all |simple_selector| {
matches_simple_selector(simple_selector, element)
}
} {
return false
}
Expand Down Expand Up @@ -193,25 +190,37 @@ fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
}

#[inline]
fn matches_simple_selector<E: ElementLike>(selector: &SimpleSelector, element: &E) -> bool {
fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
selector: &SimpleSelector, element: &T) -> bool {
static WHITESPACE: &'static [char] = &'static [' ', '\t', '\n', '\r', '\x0C'];

match *selector {
// TODO: case-sensitivity depends on the document type
// TODO: intern element names
LocalNameSelector(ref name)
=> element.get_local_name().eq_ignore_ascii_case(name.as_slice()),
LocalNameSelector(ref name) => {
do element.with_imm_element_like |element: &E| {
element.get_local_name().eq_ignore_ascii_case(name.as_slice())
}
}
NamespaceSelector(_) => false, // TODO, when the DOM supports namespaces on elements.
// TODO: case-sensitivity depends on the document type and quirks mode
// TODO: cache and intern IDs on elements.
IDSelector(ref id) => element.get_attr("id") == Some(id.as_slice()),
IDSelector(ref id) => {
do element.with_imm_element_like |element: &E| {
element.get_attr("id") == Some(id.as_slice())
}
}
// TODO: cache and intern classe names on elements.
ClassSelector(ref class) => match element.get_attr("class") {
None => false,
// TODO: case-sensitivity depends on the document type and quirks mode
Some(ref class_attr)
=> class_attr.split_iter(WHITESPACE).any(|c| c == class.as_slice()),
},
ClassSelector(ref class) => {
do element.with_imm_element_like |element: &E| {
match element.get_attr("class") {
None => false,
// TODO: case-sensitivity depends on the document type and quirks mode
Some(ref class_attr)
=> class_attr.split_iter(WHITESPACE).any(|c| c == class.as_slice()),
}
}
}

AttrExists(ref attr) => match_attribute(attr, element, |_| true),
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
Expand All @@ -232,20 +241,41 @@ fn matches_simple_selector<E: ElementLike>(selector: &SimpleSelector, element: &
attr_value.ends_with(value.as_slice())
},

FirstChild => matches_first_child(element),

Negation(ref negated) => {
!negated.iter().all(|s| matches_simple_selector(s, element))
},
}
}

#[inline]
fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
element: &T) -> bool {
let mut node = element.clone();
loop {
match node.node().prev_sibling() {
Some(prev_sibling) => {
node = prev_sibling;
if node.is_element() {
return false
}
}
None => return !element.is_root(),
}
}
}

#[inline]
fn match_attribute<E: ElementLike>(attr: &AttrSelector, element: &E, f: &fn(&str)-> bool) -> bool {
match attr.namespace {
Some(_) => false, // TODO, when the DOM supports namespaces on attributes
None => match element.get_attr(attr.name) {
None => false,
Some(ref value) => f(value.as_slice())
fn match_attribute<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool {
do element.with_imm_element_like |element: &E| {
match attr.namespace {
Some(_) => false, // TODO, when the DOM supports namespaces on attributes
None => match element.get_attr(attr.name) {
None => false,
Some(ref value) => f(value.as_slice())
}
}
}
}
7 changes: 5 additions & 2 deletions src/components/style/selectors.rs
Expand Up @@ -58,6 +58,7 @@ pub enum SimpleSelector {
AttrSuffixMatch(AttrSelector, ~str), // [foo$=bar]

// Pseudo-classes
FirstChild,
// Empty,
// Root,
// Lang(~str),
Expand Down Expand Up @@ -180,6 +181,7 @@ fn compute_specificity(mut selector: &CompoundSelector,
&ClassSelector(*)
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
| &FirstChild
// | &Empty | &Root | &Lang(*) | &NthChild(*)
=> specificity.class_like_selectors += 1,
&NamespaceSelector(*) => (),
Expand Down Expand Up @@ -272,7 +274,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
},
_ => fail!("Implementation error, this should not happen."),
},
Some(&Delim(':')) => {
Some(&Colon) => {
iter.next();
match iter.next() {
Some(Ident(name)) => match parse_simple_pseudo_class(name) {
Expand All @@ -292,7 +294,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
None => None,
Some(simple_selector) => Some(Some(Left(simple_selector))),
},
Some(Delim(':')) => {
Some(Colon) => {
match iter.next() {
Some(Ident(name)) => match parse_pseudo_element(name) {
Some(pseudo_element) => Some(Some(Right(pseudo_element))),
Expand Down Expand Up @@ -414,6 +416,7 @@ fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMa

fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
match name.to_ascii_lower().as_slice() {
"first-child" => Some(FirstChild),
// "root" => Some(Root),
// "empty" => Some(Empty),
_ => None
Expand Down
2 changes: 2 additions & 0 deletions src/components/util/tree.rs
Expand Up @@ -239,6 +239,8 @@ pub trait TreeNodeRef<Node>: Clone {
}

fn is_element(&self) -> bool;

fn is_root(&self) -> bool;
}

pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> {
Expand Down

5 comments on commit 6dba191

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

@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/selector-parsing+first-child = 6dba191 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/selector-parsing+first-child = 6dba191 merged ok, testing candidate = 071ad13

@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 = 071ad13

Please sign in to comment.