diff options
-rw-r--r-- | src/components/script/dom/node.rs | 8 | ||||
-rw-r--r-- | src/components/style/selector_matching.rs | 70 | ||||
-rw-r--r-- | src/components/style/selectors.rs | 7 | ||||
-rw-r--r-- | src/components/util/tree.rs | 2 |
4 files changed, 63 insertions, 24 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 8b5478fefe2..98ae7237283 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -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> { @@ -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>> { @@ -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() } diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs index d6c7d75fdd0..1ced3f6908e 100644 --- a/src/components/style/selector_matching.rs +++ b/src/components/style/selector_matching.rs @@ -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 } @@ -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()), @@ -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()) + } } } } diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs index 5556d74ed14..e4c1dfaa981 100644 --- a/src/components/style/selectors.rs +++ b/src/components/style/selectors.rs @@ -58,6 +58,7 @@ pub enum SimpleSelector { AttrSuffixMatch(AttrSelector, ~str), // [foo$=bar] // Pseudo-classes + FirstChild, // Empty, // Root, // Lang(~str), @@ -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(*) => (), @@ -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) { @@ -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))), @@ -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 diff --git a/src/components/util/tree.rs b/src/components/util/tree.rs index 73fdd14085d..4c6cfaa4962 100644 --- a/src/components/util/tree.rs +++ b/src/components/util/tree.rs @@ -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> { |