mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Fix case sensitivity of local name selectors.
This commit is contained in:
parent
06efa195e8
commit
639a6c51bf
6 changed files with 117 additions and 89 deletions
|
@ -265,13 +265,11 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool {
|
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool {
|
||||||
let name = unsafe {
|
assert!(self.is_element())
|
||||||
let element: JS<Element> = self.node.transmute_copy();
|
let name = if self.is_html_element_in_html_document() {
|
||||||
if element.html_element_in_html_document_for_layout() {
|
attr.lower_name.as_slice()
|
||||||
attr.lower_name.as_slice()
|
} else {
|
||||||
} else {
|
attr.name.as_slice()
|
||||||
attr.name.as_slice()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
match attr.namespace {
|
match attr.namespace {
|
||||||
SpecificNamespace(ref ns) => {
|
SpecificNamespace(ref ns) => {
|
||||||
|
@ -283,6 +281,15 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
AnyNamespace => false,
|
AnyNamespace => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_html_element_in_html_document(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
self.is_element() && {
|
||||||
|
let element: JS<Element> = self.node.transmute_copy();
|
||||||
|
element.html_element_in_html_document_for_layout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutNodeChildrenIterator<'a> {
|
pub struct LayoutNodeChildrenIterator<'a> {
|
||||||
|
|
|
@ -1997,29 +1997,32 @@ impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> {
|
||||||
fn parent_node(&self) -> Option<JSRef<'a, Node>> {
|
fn parent_node(&self) -> Option<JSRef<'a, Node>> {
|
||||||
(self as &NodeHelpers).parent_node().map(|node| *node.root())
|
(self as &NodeHelpers).parent_node().map(|node| *node.root())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prev_sibling(&self) -> Option<JSRef<'a, Node>> {
|
fn prev_sibling(&self) -> Option<JSRef<'a, Node>> {
|
||||||
(self as &NodeHelpers).prev_sibling().map(|node| *node.root())
|
(self as &NodeHelpers).prev_sibling().map(|node| *node.root())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_sibling(&self) -> Option<JSRef<'a, Node>> {
|
fn next_sibling(&self) -> Option<JSRef<'a, Node>> {
|
||||||
(self as &NodeHelpers).next_sibling().map(|node| *node.root())
|
(self as &NodeHelpers).next_sibling().map(|node| *node.root())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_document(&self) -> bool {
|
fn is_document(&self) -> bool {
|
||||||
(self as &NodeHelpers).is_document()
|
(self as &NodeHelpers).is_document()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_element(&self) -> bool {
|
fn is_element(&self) -> bool {
|
||||||
(self as &NodeHelpers).is_element()
|
(self as &NodeHelpers).is_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_element(&self) -> JSRef<'a, Element> {
|
fn as_element(&self) -> JSRef<'a, Element> {
|
||||||
let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self);
|
let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self);
|
||||||
assert!(elem.is_some());
|
assert!(elem.is_some());
|
||||||
*elem.unwrap()
|
*elem.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_attr(&self, attr: &style::AttrSelector, test: |&str| -> bool) -> bool {
|
fn match_attr(&self, attr: &style::AttrSelector, test: |&str| -> bool) -> bool {
|
||||||
let name = {
|
let name = {
|
||||||
let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self);
|
if self.is_html_element_in_html_document() {
|
||||||
assert!(elem.is_some());
|
|
||||||
let elem: &ElementHelpers = elem.unwrap() as &ElementHelpers;
|
|
||||||
if elem.html_element_in_html_document() {
|
|
||||||
attr.lower_name.as_slice()
|
attr.lower_name.as_slice()
|
||||||
} else {
|
} else {
|
||||||
attr.name.as_slice()
|
attr.name.as_slice()
|
||||||
|
@ -2034,6 +2037,13 @@ impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> {
|
||||||
style::AnyNamespace => false,
|
style::AnyNamespace => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_html_element_in_html_document(&self) -> bool {
|
||||||
|
let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self);
|
||||||
|
assert!(elem.is_some());
|
||||||
|
let elem: &ElementHelpers = elem.unwrap() as &ElementHelpers;
|
||||||
|
elem.html_element_in_html_document()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DisabledStateHelpers {
|
pub trait DisabledStateHelpers {
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub trait TNode<E:TElement> : Clone {
|
||||||
fn is_element(&self) -> bool;
|
fn is_element(&self) -> bool;
|
||||||
fn as_element(&self) -> E;
|
fn as_element(&self) -> E;
|
||||||
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool;
|
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool;
|
||||||
|
fn is_html_element_in_html_document(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TElement {
|
pub trait TElement {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::collections::hashmap::HashMap;
|
use std::collections::hashmap::HashMap;
|
||||||
use std::ascii::StrAsciiExt;
|
use std::hash::Hash;
|
||||||
use std::num::div_rem;
|
use std::num::div_rem;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
|
@ -52,7 +52,10 @@ struct SelectorMap {
|
||||||
// TODO: Tune the initial capacity of the HashMap
|
// TODO: Tune the initial capacity of the HashMap
|
||||||
id_hash: HashMap<Atom, Vec<Rule>>,
|
id_hash: HashMap<Atom, Vec<Rule>>,
|
||||||
class_hash: HashMap<Atom, Vec<Rule>>,
|
class_hash: HashMap<Atom, Vec<Rule>>,
|
||||||
element_hash: HashMap<Atom, Vec<Rule>>,
|
local_name_hash: HashMap<Atom, Vec<Rule>>,
|
||||||
|
/// Same as local_name_hash, but keys are lower-cased.
|
||||||
|
/// For HTML elements in HTML documents.
|
||||||
|
lower_local_name_hash: HashMap<Atom, Vec<Rule>>,
|
||||||
// For Rules that don't have ID, class, or element selectors.
|
// For Rules that don't have ID, class, or element selectors.
|
||||||
universal_rules: Vec<Rule>,
|
universal_rules: Vec<Rule>,
|
||||||
/// Whether this hash is empty.
|
/// Whether this hash is empty.
|
||||||
|
@ -64,7 +67,8 @@ impl SelectorMap {
|
||||||
SelectorMap {
|
SelectorMap {
|
||||||
id_hash: HashMap::new(),
|
id_hash: HashMap::new(),
|
||||||
class_hash: HashMap::new(),
|
class_hash: HashMap::new(),
|
||||||
element_hash: HashMap::new(),
|
local_name_hash: HashMap::new(),
|
||||||
|
lower_local_name_hash: HashMap::new(),
|
||||||
universal_rules: vec!(),
|
universal_rules: vec!(),
|
||||||
empty: true,
|
empty: true,
|
||||||
}
|
}
|
||||||
|
@ -113,13 +117,16 @@ impl SelectorMap {
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML elements in HTML documents must be matched case-insensitively.
|
let local_name_hash = if node.is_html_element_in_html_document() {
|
||||||
// TODO(pradeep): Case-sensitivity depends on the document type.
|
&self.lower_local_name_hash
|
||||||
SelectorMap::get_matching_rules_from_hash_ignoring_case(node,
|
} else {
|
||||||
&self.element_hash,
|
&self.local_name_hash
|
||||||
element.get_local_name().as_slice(),
|
};
|
||||||
matching_rules_list,
|
SelectorMap::get_matching_rules_from_hash(node,
|
||||||
shareable);
|
local_name_hash,
|
||||||
|
element.get_local_name(),
|
||||||
|
matching_rules_list,
|
||||||
|
shareable);
|
||||||
|
|
||||||
SelectorMap::get_matching_rules(node,
|
SelectorMap::get_matching_rules(node,
|
||||||
self.universal_rules.as_slice(),
|
self.universal_rules.as_slice(),
|
||||||
|
@ -150,23 +157,6 @@ impl SelectorMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matching_rules_from_hash_ignoring_case<E:TElement,
|
|
||||||
N:TNode<E>,
|
|
||||||
V:VecLike<DeclarationBlock>>(
|
|
||||||
node: &N,
|
|
||||||
hash: &HashMap<Atom, Vec<Rule>>,
|
|
||||||
key: &str,
|
|
||||||
matching_rules: &mut V,
|
|
||||||
shareable: &mut bool) {
|
|
||||||
// FIXME: Precache the lower case version as an atom.
|
|
||||||
match hash.find(&Atom::from_slice(key.to_ascii_lower().as_slice())) {
|
|
||||||
Some(rules) => {
|
|
||||||
SelectorMap::get_matching_rules(node, rules.as_slice(), matching_rules, shareable)
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
||||||
fn get_matching_rules<E:TElement,
|
fn get_matching_rules<E:TElement,
|
||||||
N:TNode<E>,
|
N:TNode<E>,
|
||||||
|
@ -183,49 +173,29 @@ impl SelectorMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert rule into the correct hash.
|
/// Insert rule into the correct hash.
|
||||||
/// Order in which to try: id_hash, class_hash, element_hash, universal_rules.
|
/// Order in which to try: id_hash, class_hash, local_name_hash, universal_rules.
|
||||||
fn insert(&mut self, rule: Rule) {
|
fn insert(&mut self, rule: Rule) {
|
||||||
self.empty = false;
|
self.empty = false;
|
||||||
|
|
||||||
match SelectorMap::get_id_name(&rule) {
|
match SelectorMap::get_id_name(&rule) {
|
||||||
Some(id_name) => {
|
Some(id_name) => {
|
||||||
match self.id_hash.find_mut(&id_name) {
|
self.id_hash.find_push(id_name, rule);
|
||||||
Some(rules) => {
|
|
||||||
rules.push(rule);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
self.id_hash.insert(id_name, vec!(rule));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
match SelectorMap::get_class_name(&rule) {
|
match SelectorMap::get_class_name(&rule) {
|
||||||
Some(class_name) => {
|
Some(class_name) => {
|
||||||
match self.class_hash.find_mut(&class_name) {
|
self.class_hash.find_push(class_name, rule);
|
||||||
Some(rules) => {
|
|
||||||
rules.push(rule);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
self.class_hash.insert(class_name, vec!(rule));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match SelectorMap::get_element_name(&rule) {
|
match SelectorMap::get_local_name(&rule) {
|
||||||
Some(element_name) => {
|
Some(LocalNameSelector { name, lower_name }) => {
|
||||||
match self.element_hash.find_mut(&element_name) {
|
self.local_name_hash.find_push(name, rule.clone());
|
||||||
Some(rules) => {
|
self.lower_local_name_hash.find_push(lower_name, rule);
|
||||||
rules.push(rule);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
self.element_hash.insert(element_name, vec!(rule));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -263,14 +233,12 @@ impl SelectorMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the name if it is a type selector, or None otherwise.
|
/// Retrieve the name if it is a type selector, or None otherwise.
|
||||||
fn get_element_name(rule: &Rule) -> Option<Atom> {
|
fn get_local_name(rule: &Rule) -> Option<LocalNameSelector> {
|
||||||
let simple_selector_sequence = &rule.selector.simple_selectors;
|
let simple_selector_sequence = &rule.selector.simple_selectors;
|
||||||
for ss in simple_selector_sequence.iter() {
|
for ss in simple_selector_sequence.iter() {
|
||||||
match *ss {
|
match *ss {
|
||||||
// HTML elements in HTML documents must be matched case-insensitively
|
|
||||||
// TODO: case-sensitivity depends on the document type
|
|
||||||
LocalNameSelector(ref name) => {
|
LocalNameSelector(ref name) => {
|
||||||
return Some(Atom::from_slice(name.as_slice().to_ascii_lower().as_slice()));
|
return Some(name.clone())
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -629,11 +597,10 @@ fn matches_simple_selector<E:TElement,
|
||||||
shareable: &mut bool)
|
shareable: &mut bool)
|
||||||
-> bool {
|
-> bool {
|
||||||
match *selector {
|
match *selector {
|
||||||
// TODO: case-sensitivity depends on the document type
|
LocalNameSelector(LocalNameSelector { ref name, ref lower_name }) => {
|
||||||
// TODO: intern element names
|
let name = if element.is_html_element_in_html_document() { lower_name } else { name };
|
||||||
LocalNameSelector(ref name) => {
|
|
||||||
let element = element.as_element();
|
let element = element.as_element();
|
||||||
element.get_local_name().as_slice().eq_ignore_ascii_case(name.as_slice())
|
element.get_local_name() == name
|
||||||
}
|
}
|
||||||
|
|
||||||
NamespaceSelector(ref namespace) => {
|
NamespaceSelector(ref namespace) => {
|
||||||
|
@ -918,11 +885,30 @@ fn matches_last_child<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trait FindPush<K, V> {
|
||||||
|
fn find_push(&mut self, key: K, value: V);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Eq + Hash, V> FindPush<K, V> for HashMap<K, Vec<V>> {
|
||||||
|
fn find_push(&mut self, key: K, value: V) {
|
||||||
|
match self.find_mut(&key) {
|
||||||
|
Some(vec) => {
|
||||||
|
vec.push(value);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
self.insert(key, vec![value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use servo_util::atom::Atom;
|
use servo_util::atom::Atom;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
use super::{DeclarationBlock, Rule, SelectorMap};
|
use super::{DeclarationBlock, Rule, SelectorMap};
|
||||||
|
use selectors::LocalNameSelector;
|
||||||
|
|
||||||
/// Helper method to get some Rules from selector strings.
|
/// Helper method to get some Rules from selector strings.
|
||||||
/// Each sublist of the result contains the Rules for one StyleRule.
|
/// Each sublist of the result contains the Rules for one StyleRule.
|
||||||
|
@ -971,12 +957,18 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_element_name(){
|
fn test_get_local_name(){
|
||||||
let rules_list = get_mock_rules(["img.foo", "#top", "IMG", "ImG"]);
|
let rules_list = get_mock_rules(["img.foo", "#top", "IMG", "ImG"]);
|
||||||
assert_eq!(SelectorMap::get_element_name(&rules_list[0][0]), Some(Atom::from_slice("img")));
|
let check = |i, names: Option<(&str, &str)>| {
|
||||||
assert_eq!(SelectorMap::get_element_name(&rules_list[1][0]), None);
|
assert!(SelectorMap::get_local_name(&rules_list[i][0])
|
||||||
assert_eq!(SelectorMap::get_element_name(&rules_list[2][0]), Some(Atom::from_slice("img")));
|
== names.map(|(name, lower_name)| LocalNameSelector {
|
||||||
assert_eq!(SelectorMap::get_element_name(&rules_list[3][0]), Some(Atom::from_slice("img")));
|
name: Atom::from_slice(name),
|
||||||
|
lower_name: Atom::from_slice(lower_name) }))
|
||||||
|
};
|
||||||
|
check(0, Some(("img", "img")));
|
||||||
|
check(1, None);
|
||||||
|
check(2, Some(("IMG", "img")));
|
||||||
|
check(3, Some(("ImG", "img")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::{cmp, iter};
|
use std::{cmp, iter};
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::{StrAsciiExt, OwnedStrAsciiExt};
|
||||||
use std::vec;
|
use std::vec;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ pub enum Combinator {
|
||||||
pub enum SimpleSelector {
|
pub enum SimpleSelector {
|
||||||
IDSelector(Atom),
|
IDSelector(Atom),
|
||||||
ClassSelector(Atom),
|
ClassSelector(Atom),
|
||||||
LocalNameSelector(Atom),
|
LocalNameSelector(LocalNameSelector),
|
||||||
NamespaceSelector(Namespace),
|
NamespaceSelector(Namespace),
|
||||||
|
|
||||||
// Attribute selectors
|
// Attribute selectors
|
||||||
|
@ -93,6 +93,12 @@ pub enum SimpleSelector {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(PartialEq, Clone)]
|
||||||
|
pub struct LocalNameSelector {
|
||||||
|
pub name: Atom,
|
||||||
|
pub lower_name: Atom,
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Clone)]
|
#[deriving(PartialEq, Clone)]
|
||||||
pub struct AttrSelector {
|
pub struct AttrSelector {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -268,8 +274,10 @@ fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
}
|
}
|
||||||
match local_name {
|
match local_name {
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
let name_atom = Atom::from_slice(name.as_slice());
|
simple_selectors.push(LocalNameSelector(LocalNameSelector {
|
||||||
simple_selectors.push(LocalNameSelector(name_atom))
|
name: Atom::from_slice(name.as_slice()),
|
||||||
|
lower_name: Atom::from_slice(name.into_ascii_lower().as_slice())
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
@ -574,9 +582,11 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parsing() {
|
fn test_parsing() {
|
||||||
assert!(parse("") == Err(()))
|
assert!(parse("") == Err(()))
|
||||||
assert!(parse("e") == Ok(vec!(Selector {
|
assert!(parse("EeÉ") == Ok(vec!(Selector {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(LocalNameSelector(Atom::from_slice("e"))),
|
simple_selectors: vec!(LocalNameSelector(LocalNameSelector {
|
||||||
|
name: Atom::from_slice("EeÉ"),
|
||||||
|
lower_name: Atom::from_slice("eeÉ") })),
|
||||||
next: None,
|
next: None,
|
||||||
}),
|
}),
|
||||||
pseudo_element: None,
|
pseudo_element: None,
|
||||||
|
@ -600,7 +610,9 @@ mod tests {
|
||||||
})))
|
})))
|
||||||
assert!(parse("e.foo#bar") == Ok(vec!(Selector {
|
assert!(parse("e.foo#bar") == Ok(vec!(Selector {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(LocalNameSelector(Atom::from_slice("e")),
|
simple_selectors: vec!(LocalNameSelector(LocalNameSelector {
|
||||||
|
name: Atom::from_slice("e"),
|
||||||
|
lower_name: Atom::from_slice("e") }),
|
||||||
ClassSelector(Atom::from_slice("foo")),
|
ClassSelector(Atom::from_slice("foo")),
|
||||||
IDSelector(Atom::from_slice("bar"))),
|
IDSelector(Atom::from_slice("bar"))),
|
||||||
next: None,
|
next: None,
|
||||||
|
@ -612,7 +624,9 @@ mod tests {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))),
|
simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))),
|
||||||
next: Some((box CompoundSelector {
|
next: Some((box CompoundSelector {
|
||||||
simple_selectors: vec!(LocalNameSelector(Atom::from_slice("e")),
|
simple_selectors: vec!(LocalNameSelector(LocalNameSelector {
|
||||||
|
name: Atom::from_slice("e"),
|
||||||
|
lower_name: Atom::from_slice("e") }),
|
||||||
ClassSelector(Atom::from_slice("foo"))),
|
ClassSelector(Atom::from_slice("foo"))),
|
||||||
next: None,
|
next: None,
|
||||||
}, Descendant)),
|
}, Descendant)),
|
||||||
|
@ -655,7 +669,9 @@ mod tests {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(
|
simple_selectors: vec!(
|
||||||
NamespaceSelector(namespace::MathML),
|
NamespaceSelector(namespace::MathML),
|
||||||
LocalNameSelector(Atom::from_slice("e")),
|
LocalNameSelector(LocalNameSelector {
|
||||||
|
name: Atom::from_slice("e"),
|
||||||
|
lower_name: Atom::from_slice("e") }),
|
||||||
),
|
),
|
||||||
next: None,
|
next: None,
|
||||||
}),
|
}),
|
||||||
|
@ -675,7 +691,9 @@ mod tests {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(),
|
simple_selectors: vec!(),
|
||||||
next: Some((box CompoundSelector {
|
next: Some((box CompoundSelector {
|
||||||
simple_selectors: vec!(LocalNameSelector(Atom::from_slice("div"))),
|
simple_selectors: vec!(LocalNameSelector(LocalNameSelector {
|
||||||
|
name: Atom::from_slice("div"),
|
||||||
|
lower_name: Atom::from_slice("div") })),
|
||||||
next: None,
|
next: None,
|
||||||
}, Descendant)),
|
}, Descendant)),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub use properties::longhands;
|
||||||
pub use node::{TElement, TNode};
|
pub use node::{TElement, TNode};
|
||||||
pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace};
|
pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace};
|
||||||
pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelector, Combinator};
|
pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelector, Combinator};
|
||||||
pub use selectors::{parse_selector_list};
|
pub use selectors::{LocalNameSelector, parse_selector_list};
|
||||||
pub use namespaces::NamespaceMap;
|
pub use namespaces::NamespaceMap;
|
||||||
pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType};
|
pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType};
|
||||||
pub use font_face::{FontFaceFormat, FontFaceRule, FontFaceSource,FontFaceSourceLine, TtfFormat};
|
pub use font_face::{FontFaceFormat, FontFaceRule, FontFaceSource,FontFaceSourceLine, TtfFormat};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue