aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Taubert <tim@timtaubert.de>2014-10-06 16:02:19 +0200
committerTim Taubert <tim@timtaubert.de>2014-10-08 11:01:31 +0200
commitb9e23563bb9940ece621d3f6a969a5e08e1bd82b (patch)
tree981ee905456f2cb51975f6955ae75344569ec8fc
parent070b6046aa9a7869e2ca53f69d7a349afbec09c4 (diff)
downloadservo-b9e23563bb9940ece621d3f6a969a5e08e1bd82b.tar.gz
servo-b9e23563bb9940ece621d3f6a969a5e08e1bd82b.zip
Support [*|attr], attribute selectors in any namespace (fixes #1558)
-rw-r--r--components/layout/wrapper.rs11
-rw-r--r--components/script/dom/element.rs39
-rw-r--r--components/script/dom/node.rs10
-rw-r--r--components/style/node.rs1
-rw-r--r--tests/ref/attr_exists_selector.html4
-rw-r--r--tests/ref/attr_exists_selector_ref.html1
-rw-r--r--tests/ref/noteq_attr_exists_selector.html1
7 files changed, 57 insertions, 10 deletions
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index 40a77935129..c9f9df91bec 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -310,8 +310,10 @@ impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
element.get_attr(ns, name)
.map_or(false, |attr| test(attr))
},
- // FIXME: https://github.com/mozilla/servo/issues/1558
- AnyNamespace => false,
+ AnyNamespace => {
+ let element = self.as_element();
+ element.get_attrs(name).iter().any(|attr| test(*attr))
+ }
}
}
@@ -414,6 +416,11 @@ impl<'le> TElement<'le> for LayoutElement<'le> {
unsafe { self.element.get_attr_val_for_layout(namespace, name) }
}
+ #[inline]
+ fn get_attrs(self, name: &str) -> Vec<&'le str> {
+ unsafe { self.element.get_attr_vals_for_layout(name) }
+ }
+
fn get_link(self) -> Option<&'le str> {
// FIXME: This is HTML only.
match self.element.node.type_id_for_layout() {
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index a3960116ab2..681951136a0 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -170,6 +170,7 @@ impl Element {
pub trait RawLayoutElementHelpers {
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &str) -> Option<&'a str>;
+ unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &str) -> Vec<&'a str>;
unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str) -> Option<Atom>;
unsafe fn has_class_for_layout(&self, name: &str) -> bool;
}
@@ -193,6 +194,21 @@ impl RawLayoutElementHelpers for Element {
#[inline]
#[allow(unrooted_must_root)]
+ unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &str) -> Vec<&'a str> {
+ // cast to point to T in RefCell<T> directly
+ let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs);
+ (*attrs).iter().filter_map(|attr: &JS<Attr>| {
+ let attr = attr.unsafe_get();
+ if name == (*attr).local_name_atom_forever().as_slice() {
+ Some((*attr).value_ref_forever())
+ } else {
+ None
+ }
+ }).collect()
+ }
+
+ #[inline]
+ #[allow(unrooted_must_root)]
unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str)
-> Option<Atom> {
// cast to point to T in RefCell<T> directly
@@ -291,6 +307,8 @@ pub trait AttributeHandlers {
/// name, if any.
fn get_attribute(self, namespace: Namespace, local_name: &str)
-> Option<Temporary<Attr>>;
+ fn get_attributes(self, local_name: &str)
+ -> Vec<Temporary<Attr>>;
fn set_attribute_from_parser(self, local_name: Atom,
value: DOMString, namespace: Namespace,
prefix: Option<DOMString>);
@@ -321,10 +339,20 @@ pub trait AttributeHandlers {
impl<'a> AttributeHandlers for JSRef<'a, Element> {
fn get_attribute(self, namespace: Namespace, local_name: &str) -> Option<Temporary<Attr>> {
+ self.get_attributes(local_name).iter().map(|attr| attr.root())
+ .find(|attr| attr.namespace == namespace)
+ .map(|x| Temporary::from_rooted(*x))
+ }
+
+ fn get_attributes(self, local_name: &str) -> Vec<Temporary<Attr>> {
let local_name = Atom::from_slice(local_name);
- self.attrs.borrow().iter().map(|attr| attr.root()).find(|attr| {
- *attr.local_name() == local_name && attr.namespace == namespace
- }).map(|x| Temporary::from_rooted(*x))
+ self.attrs.borrow().iter().map(|attr| attr.root()).filter_map(|attr| {
+ if *attr.local_name() == local_name {
+ Some(Temporary::from_rooted(*attr))
+ } else {
+ None
+ }
+ }).collect()
}
fn set_attribute_from_parser(self, local_name: Atom,
@@ -947,6 +975,11 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> {
unsafe { mem::transmute(attr.deref().value().as_slice()) }
})
}
+ fn get_attrs(self, attr: &str) -> Vec<&'a str> {
+ self.get_attributes(attr).iter().map(|attr| attr.root()).map(|attr| {
+ unsafe { mem::transmute(attr.deref().value().as_slice()) }
+ }).collect()
+ }
fn get_link(self) -> Option<&'a str> {
// FIXME: This is HTML only.
let node: JSRef<Node> = NodeCast::from_ref(self);
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index b8319bd0da4..fdee69fbf3e 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -5,7 +5,6 @@
//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
use dom::attr::{Attr, AttrHelpers};
-use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
@@ -2115,10 +2114,13 @@ impl<'a> style::TNode<'a, JSRef<'a, Element>> for JSRef<'a, Node> {
match attr.namespace {
style::SpecificNamespace(ref ns) => {
self.as_element().get_attribute(ns.clone(), name).root()
- .map_or(false, |attr| test(attr.deref().Value().as_slice()))
+ .map_or(false, |attr| test(attr.deref().value().as_slice()))
},
- // FIXME: https://github.com/mozilla/servo/issues/1558
- style::AnyNamespace => false,
+ style::AnyNamespace => {
+ self.as_element().get_attributes(name).iter()
+ .map(|attr| attr.root())
+ .any(|attr| test(attr.deref().value().as_slice()))
+ }
}
}
diff --git a/components/style/node.rs b/components/style/node.rs
index 75d098563c2..450e6655e35 100644
--- a/components/style/node.rs
+++ b/components/style/node.rs
@@ -23,6 +23,7 @@ pub trait TNode<'a, E: TElement<'a>> : Clone + Copy {
pub trait TElement<'a> : Copy {
fn get_attr(self, namespace: &Namespace, attr: &str) -> Option<&'a str>;
+ fn get_attrs(self, attr: &str) -> Vec<&'a str>;
fn get_link(self) -> Option<&'a str>;
fn get_local_name(self) -> &'a Atom;
fn get_namespace(self) -> &'a Namespace;
diff --git a/tests/ref/attr_exists_selector.html b/tests/ref/attr_exists_selector.html
index 6d8f01e16aa..43ad48bb62a 100644
--- a/tests/ref/attr_exists_selector.html
+++ b/tests/ref/attr_exists_selector.html
@@ -1,13 +1,15 @@
<!DOCTYPE html>
<html>
<head>
- <title>Attribute exists selector: [foo]</title>
+ <title>Attribute exists selector: [foo] and [*|foo]</title>
<style>
p[data-green] { color: green }
+ p[*|data-red] { color: red }
</style>
</head>
<body>
<p data-green="">This text should be green.</p>
+ <p data-red="">This text should be red.</p>
<p>This text should be black.</p>
</body>
</html>
diff --git a/tests/ref/attr_exists_selector_ref.html b/tests/ref/attr_exists_selector_ref.html
index 522883d8ed4..ba75fc54945 100644
--- a/tests/ref/attr_exists_selector_ref.html
+++ b/tests/ref/attr_exists_selector_ref.html
@@ -5,6 +5,7 @@
</head>
<body>
<p style="color: green">This text should be green.</p>
+ <p style="color: red">This text should be red.</p>
<p>This text should be black.</p>
</body>
</html>
diff --git a/tests/ref/noteq_attr_exists_selector.html b/tests/ref/noteq_attr_exists_selector.html
index 58bce6d5d39..c335c166985 100644
--- a/tests/ref/noteq_attr_exists_selector.html
+++ b/tests/ref/noteq_attr_exists_selector.html
@@ -5,6 +5,7 @@
</head>
<body>
<p>This text should be green.</p>
+ <p>This text should be red.</p>
<p>This text should be black.</p>
</body>
</html>