diff options
-rw-r--r-- | components/style/selector_matching.rs | 8 | ||||
-rw-r--r-- | components/style/selectors.rs | 55 | ||||
-rw-r--r-- | tests/ref/attr_selector_case_sensitivity.html | 17 | ||||
-rw-r--r-- | tests/ref/attr_selector_case_sensitivity_ref.html | 17 | ||||
-rw-r--r-- | tests/ref/basic.list | 1 |
5 files changed, 81 insertions, 17 deletions
diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index fc37688cea0..9ab97a29cd3 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::ascii::AsciiExt; use std::collections::hashmap::HashMap; use std::hash::Hash; use std::num::div_rem; @@ -723,14 +724,17 @@ pub fn matches_simple_selector<'a, E:TElement<'a>, *shareable = false; element.match_attr(attr, |_| true) } - AttrEqual(ref attr, ref value) => { + AttrEqual(ref attr, ref value, case_sensitivity) => { if value.as_slice() != "DIR" { // FIXME(pcwalton): Remove once we start actually supporting RTL text. This is in // here because the UA style otherwise disables all style sharing completely. *shareable = false } element.match_attr(attr, |attr_value| { - attr_value == value.as_slice() + match case_sensitivity { + CaseSensitive => attr_value == value.as_slice(), + CaseInsensitive => attr_value.eq_ignore_ascii_case(value.as_slice()), + } }) } AttrIncludes(ref attr, ref value) => { diff --git a/components/style/selectors.rs b/components/style/selectors.rs index 7a6f8637cda..6c783e70349 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -61,9 +61,9 @@ pub enum SimpleSelector { // Attribute selectors AttrExists(AttrSelector), // [foo] - AttrEqual(AttrSelector, String), // [foo=bar] + AttrEqual(AttrSelector, String, CaseSensitivity), // [foo=bar] AttrIncludes(AttrSelector, String), // [foo~=bar] - AttrDashMatch(AttrSelector, String, String), // [foo|=bar] Second string is the first + "-" + AttrDashMatch(AttrSelector, String, String), // [foo|=bar] Second string is the first + "-" AttrPrefixMatch(AttrSelector, String), // [foo^=bar] AttrSubstringMatch(AttrSelector, String), // [foo*=bar] AttrSuffixMatch(AttrSelector, String), // [foo$=bar] @@ -90,6 +90,14 @@ pub enum SimpleSelector { // ... } + +#[deriving(Eq, PartialEq, Clone, Hash)] +pub enum CaseSensitivity { + CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive. + CaseInsensitive, +} + + #[deriving(Eq, PartialEq, Clone, Hash)] pub struct LocalName { pub name: Atom, @@ -446,25 +454,21 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace }; skip_whitespace(iter); // TODO: deal with empty value or value containing whitespace (see spec) - macro_rules! get_value( () => {{ - skip_whitespace(iter); - match iter.next() { - Some(Ident(value)) | Some(QuotedString(value)) => value, - _ => return Err(()) - } - }};) let result = match iter.next() { None => AttrExists(attr), // [foo] - Some(Delim('=')) => AttrEqual(attr, (get_value!())), // [foo=bar] - Some(IncludeMatch) => AttrIncludes(attr, (get_value!())), // [foo~=bar] + Some(Delim('=')) => AttrEqual( + attr, try!(parse_attribute_value(iter)), + try!(parse_attribute_flags(iter))), // [foo=bar] + Some(IncludeMatch) => AttrIncludes(attr, try!(parse_attribute_value(iter))), // [foo~=bar] Some(DashMatch) => { - let value = get_value!(); + let value = try!(parse_attribute_value(iter)); let dashing_value = format!("{}-", value); AttrDashMatch(attr, value, dashing_value) // [foo|=bar] }, - Some(PrefixMatch) => AttrPrefixMatch(attr, (get_value!())), // [foo^=bar] - Some(SubstringMatch) => AttrSubstringMatch(attr, (get_value!())), // [foo*=bar] - Some(SuffixMatch) => AttrSuffixMatch(attr, (get_value!())), // [foo$=bar] + Some(PrefixMatch) => AttrPrefixMatch(attr, try!(parse_attribute_value(iter))), // [foo^=bar] + // [foo*=bar] + Some(SubstringMatch) => AttrSubstringMatch(attr, try!(parse_attribute_value(iter))), + Some(SuffixMatch) => AttrSuffixMatch(attr, try!(parse_attribute_value(iter))), // [foo$=bar] _ => return Err(()) }; skip_whitespace(iter); @@ -472,6 +476,27 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace } +fn parse_attribute_value<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) -> Result<String, ()> { + skip_whitespace(iter); + match iter.next() { + Some(Ident(value)) | Some(QuotedString(value)) => Ok(value), + _ => Err(()) + } +} + + +fn parse_attribute_flags<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) + -> Result<CaseSensitivity, ()> { + skip_whitespace(iter); + match iter.next() { + None => Ok(CaseSensitive), + Some(Ident(ref value)) if value.as_slice().eq_ignore_ascii_case("i") + => Ok(CaseInsensitive), + _ => Err(()) + } +} + + fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> { match name.to_ascii_lower().as_slice() { "any-link" => Ok(AnyLink), diff --git a/tests/ref/attr_selector_case_sensitivity.html b/tests/ref/attr_selector_case_sensitivity.html new file mode 100644 index 00000000000..c4d36db7918 --- /dev/null +++ b/tests/ref/attr_selector_case_sensitivity.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute selector case-sensitivity: [foo=bar] and [foo=bar i]</title> + <style> + p[data-foo=Bar] { color: green } + p[data-foo=bar] { color: red } + p[data-foo=baz i] { color: green } + p[data-foo=baz] { color: red } + </style> + </head> + <body> + <p data-foo="Bar">This text should be green.</p> + <p data-foo="Baz">This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/tests/ref/attr_selector_case_sensitivity_ref.html b/tests/ref/attr_selector_case_sensitivity_ref.html new file mode 100644 index 00000000000..9e9be12d13e --- /dev/null +++ b/tests/ref/attr_selector_case_sensitivity_ref.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute selector case-sensitivity: [foo=bar] and [foo=bar i]</title> + <style> + p[data-foo=Bar] { color: green } + p[data-foo=bar] { color: red } + p[data-foo=baz i] { color: green } + p[data-foo=baz] { color: red } + </style> + </head> + <body> + <p style="color: green">This text should be green.</p> + <p style="color: green">This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 247f4d38d81..b2583835e37 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -30,6 +30,7 @@ # inline_border_a.html inline_border_b.html == anon_block_inherit_a.html anon_block_inherit_b.html == attr_exists_selector.html attr_exists_selector_ref.html +== attr_selector_case_sensitivity.html attr_selector_case_sensitivity_ref.html != noteq_attr_exists_selector.html attr_exists_selector_ref.html == data_img_a.html data_img_b.html == background_style_attr.html background_ref.html |