aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2014-10-10 14:26:23 +0100
committerSimon Sapin <simon.sapin@exyr.org>2014-10-10 14:29:24 +0100
commit1117d86b63ecafeef302c85fb717de4753ac2639 (patch)
tree0d871e74c5934b82c08865072cf1a2f69b2b520f
parent2f9808e1306a6468dea0de8657a4fa5868e1a126 (diff)
downloadservo-1117d86b63ecafeef302c85fb717de4753ac2639.tar.gz
servo-1117d86b63ecafeef302c85fb717de4753ac2639.zip
Add [foo=bar i] case-insensitive attribute selectors.
-rw-r--r--components/style/selector_matching.rs8
-rw-r--r--components/style/selectors.rs55
-rw-r--r--tests/ref/attr_selector_case_sensitivity.html17
-rw-r--r--tests/ref/attr_selector_case_sensitivity_ref.html17
-rw-r--r--tests/ref/basic.list1
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