diff options
-rw-r--r-- | components/script/dom/element.rs | 9 | ||||
-rw-r--r-- | components/script/layout_wrapper.rs | 15 | ||||
-rw-r--r-- | components/selectors/attr.rs | 67 | ||||
-rw-r--r-- | components/selectors/matching.rs | 138 | ||||
-rw-r--r-- | components/selectors/parser.rs | 368 | ||||
-rw-r--r-- | components/selectors/size_of_tests.rs | 3 | ||||
-rw-r--r-- | components/selectors/tree.rs | 20 | ||||
-rw-r--r-- | components/selectors/visitor.rs | 11 | ||||
-rw-r--r-- | components/style/attr.rs | 6 | ||||
-rw-r--r-- | components/style/gecko/snapshot.rs | 10 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 11 | ||||
-rw-r--r-- | components/style/restyle_hints.rs | 22 | ||||
-rw-r--r-- | components/style/servo/selector_parser.rs | 13 | ||||
-rw-r--r-- | components/style/stylist.rs | 27 | ||||
-rw-r--r-- | tests/unit/style/stylesheets.rs | 18 |
15 files changed, 379 insertions, 359 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 9c6d84ba485..bdd2b49a751 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -86,10 +86,9 @@ use net_traits::request::CorsSettings; use ref_filter_map::ref_filter_map; use script_layout_interface::message::ReflowQueryType; use script_thread::Runnable; -use selectors::attr::AttrSelectorOperation; +use selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, matches_selector_list}; use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS}; -use selectors::parser::NamespaceConstraint; use servo_atoms::Atom; use std::ascii::AsciiExt; use std::borrow::Cow; @@ -2387,13 +2386,13 @@ impl<'a> ::selectors::Element for Root<Element> { } fn attr_matches(&self, - ns: &NamespaceConstraint<SelectorImpl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &LocalName, - operation: &AttrSelectorOperation<SelectorImpl>) + operation: &AttrSelectorOperation<&String>) -> bool { match *ns { NamespaceConstraint::Specific(ref ns) => { - self.get_attribute(&ns.url, local_name) + self.get_attribute(ns, local_name) .map_or(false, |attr| attr.value().eval_selector(operation)) } NamespaceConstraint::Any => { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 773937fce00..ac59921d2ea 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -50,9 +50,8 @@ use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, Truste use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; -use selectors::attr::AttrSelectorOperation; +use selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; use selectors::matching::{ElementSelectorFlags, MatchingContext}; -use selectors::parser::NamespaceConstraint; use servo_atoms::Atom; use servo_url::ServoUrl; use std::fmt; @@ -606,13 +605,13 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } fn attr_matches(&self, - ns: &NamespaceConstraint<SelectorImpl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &LocalName, - operation: &AttrSelectorOperation<SelectorImpl>) + operation: &AttrSelectorOperation<&String>) -> bool { match *ns { NamespaceConstraint::Specific(ref ns) => { - self.get_attr_enum(&ns.url, local_name) + self.get_attr_enum(ns, local_name) .map_or(false, |value| value.eval_selector(operation)) } NamespaceConstraint::Any => { @@ -1159,13 +1158,13 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { } fn attr_matches(&self, - ns: &NamespaceConstraint<SelectorImpl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &LocalName, - operation: &AttrSelectorOperation<SelectorImpl>) + operation: &AttrSelectorOperation<&String>) -> bool { match *ns { NamespaceConstraint::Specific(ref ns) => { - self.get_attr_enum(&ns.url, local_name) + self.get_attr_enum(ns, local_name) .map_or(false, |value| value.eval_selector(operation)) } NamespaceConstraint::Any => { diff --git a/components/selectors/attr.rs b/components/selectors/attr.rs index 90707c54351..f18219b2204 100644 --- a/components/selectors/attr.rs +++ b/components/selectors/attr.rs @@ -2,24 +2,54 @@ * 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 cssparser::ToCss; use parser::SelectorImpl; use std::ascii::AsciiExt; +use std::fmt; -pub enum AttrSelectorOperation<'a, Impl: SelectorImpl> where Impl::AttrValue: 'a { +#[derive(Eq, PartialEq, Clone)] +pub struct AttrSelectorWithNamespace<Impl: SelectorImpl> { + pub namespace: NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>, + pub local_name: Impl::LocalName, + pub local_name_lower: Impl::LocalName, + pub operation: AttrSelectorOperation<Impl::AttrValue>, + pub never_matches: bool, +} + +impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> { + pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> { + match self.namespace { + NamespaceConstraint::Any => NamespaceConstraint::Any, + NamespaceConstraint::Specific((_, ref url)) => { + NamespaceConstraint::Specific(url) + } + } + } +} + +#[derive(Eq, PartialEq, Clone)] +pub enum NamespaceConstraint<NamespaceUrl> { + Any, + + /// Empty string for no namespace + Specific(NamespaceUrl), +} + +#[derive(Eq, PartialEq, Clone)] +pub enum AttrSelectorOperation<AttrValue> { Exists, WithValue { operator: AttrSelectorOperator, case_sensitivity: CaseSensitivity, - expected_value: &'a Impl::AttrValue, + expected_value: AttrValue, } } -impl<'a, Impl: SelectorImpl> AttrSelectorOperation<'a, Impl> { - pub fn eval_str(&self, element_attr_value: &str) -> bool - where Impl::AttrValue: AsRef<str> { +impl<AttrValue> AttrSelectorOperation<AttrValue> { + pub fn eval_str(&self, element_attr_value: &str) -> bool where AttrValue: AsRef<str> { match *self { AttrSelectorOperation::Exists => true, - AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => { + AttrSelectorOperation::WithValue { operator, case_sensitivity, ref expected_value } => { operator.eval_str(element_attr_value, expected_value.as_ref(), case_sensitivity) } } @@ -28,12 +58,25 @@ impl<'a, Impl: SelectorImpl> AttrSelectorOperation<'a, Impl> { #[derive(Eq, PartialEq, Clone, Copy)] pub enum AttrSelectorOperator { - Equal, // = - Includes, // ~= - DashMatch, // |= - Prefix, // ^= - Substring, // *= - Suffix, // $= + Equal, + Includes, + DashMatch, + Prefix, + Substring, + Suffix, +} + +impl ToCss for AttrSelectorOperator { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(match *self { + AttrSelectorOperator::Equal => " = ", + AttrSelectorOperator::Includes => " ~= ", + AttrSelectorOperator::DashMatch => " |= ", + AttrSelectorOperator::Prefix => " ^= ", + AttrSelectorOperator::Substring => " *= ", + AttrSelectorOperator::Suffix => " $= ", + }) + } } impl AttrSelectorOperator { diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 1ec969b08e5..a11708818b3 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -2,10 +2,10 @@ * 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 attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity}; +use attr::{AttrSelectorOperation, NamespaceConstraint}; use bloom::BloomFilter; -use parser::{Combinator, ComplexSelector, Component, LocalName, NamespaceConstraint}; -use parser::{Selector, SelectorInner, SelectorIter, SelectorImpl, AttrSelector}; +use parser::{Combinator, ComplexSelector, Component, LocalName}; +use parser::{Selector, SelectorInner, SelectorIter, SelectorImpl}; use std::borrow::Borrow; use tree::Element; @@ -387,8 +387,7 @@ fn matches_simple_selector<E, F>( element.match_pseudo_element(pseudo, context) } Component::LocalName(LocalName { ref name, ref lower_name }) => { - let name = if element.is_html_element_in_html_document() { lower_name } else { name }; - element.get_local_name() == name.borrow() + element.get_local_name() == select_name(element, name, lower_name).borrow() } Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => { @@ -399,9 +398,8 @@ fn matches_simple_selector<E, F>( element.get_namespace() == url.borrow() } Component::ExplicitNoNamespace => { - // Rust type’s default, not default namespace - let empty_string = <E::Impl as SelectorImpl>::NamespaceUrl::default(); - element.get_namespace() == empty_string.borrow() + let ns = ::parser::namespace_empty_string::<E::Impl>(); + element.get_namespace() == ns.borrow() } // TODO: case-sensitivity depends on the document type and quirks mode Component::ID(ref id) => { @@ -411,63 +409,58 @@ fn matches_simple_selector<E, F>( Component::Class(ref class) => { element.has_class(class) } - Component::AttrExists(ref attr) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::Exists) - } - Component::AttrEqual(ref attr, ref value, case_sensitivity) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::WithValue { - operator: AttrSelectorOperator::Equal, - case_sensitivity: case_sensitivity, - expected_value: value - }) - } - Component::AttrIncludes(ref attr, ref value) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::WithValue { - operator: AttrSelectorOperator::Includes, - case_sensitivity: CaseSensitivity::CaseSensitive, - expected_value: value - }) - } - Component::AttrDashMatch(ref attr, ref value) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::WithValue { - operator: AttrSelectorOperator::DashMatch, - case_sensitivity: CaseSensitivity::CaseSensitive, - expected_value: value - }) - } - Component::AttrPrefixMatch(ref attr, ref value) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::WithValue { - operator: AttrSelectorOperator::Prefix, - case_sensitivity: CaseSensitivity::CaseSensitive, - expected_value: value - }) - } - Component::AttrSubstringMatch(ref attr, ref value) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::WithValue { - operator: AttrSelectorOperator::Substring, - case_sensitivity: CaseSensitivity::CaseSensitive, - expected_value: value - }) - } - Component::AttrSuffixMatch(ref attr, ref value) => { - let (ns, n) = unpack_attr_selector(element, attr); - element.attr_matches(ns, n, &AttrSelectorOperation::WithValue { - operator: AttrSelectorOperator::Suffix, - case_sensitivity: CaseSensitivity::CaseSensitive, - expected_value: value - }) - } - Component::AttrIncludesNeverMatch(..) | - Component::AttrPrefixNeverMatch(..) | - Component::AttrSubstringNeverMatch(..) | - Component::AttrSuffixNeverMatch(..) => { - false + Component::AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => { + element.attr_matches( + &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()), + select_name(element, local_name, local_name_lower), + &AttrSelectorOperation::Exists + ) + } + Component::AttributeInNoNamespace { + ref local_name, + ref local_name_lower, + ref value, + operator, + case_sensitivity, + never_matches, + } => { + if never_matches { + false + } else { + element.attr_matches( + &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()), + select_name(element, local_name, local_name_lower), + &AttrSelectorOperation::WithValue { + operator: operator, + case_sensitivity: case_sensitivity, + expected_value: value, + } + ) + } + } + Component::AttributeOther(ref attr_sel) => { + if attr_sel.never_matches { + return false + } else { + element.attr_matches( + &attr_sel.namespace(), + select_name(element, &attr_sel.local_name, &attr_sel.local_name_lower), + &match attr_sel.operation { + AttrSelectorOperation::Exists => AttrSelectorOperation::Exists, + AttrSelectorOperation::WithValue { + operator, + case_sensitivity, + ref expected_value, + } => { + AttrSelectorOperation::WithValue { + operator: operator, + case_sensitivity: case_sensitivity, + expected_value: expected_value, + } + } + } + ) + } } Component::NonTSPseudoClass(ref pc) => { element.match_non_ts_pseudo_class(pc, context, flags_setter) @@ -519,16 +512,15 @@ fn matches_simple_selector<E, F>( } } -fn unpack_attr_selector<'a, E>(element: &E, attr: &'a AttrSelector<E::Impl>) - -> (&'a NamespaceConstraint<E::Impl>, - &'a <E::Impl as SelectorImpl>::LocalName) +fn select_name<'a, E>(element: &E, local_name: &'a <E::Impl as SelectorImpl>::LocalName, + local_name_lower: &'a <E::Impl as SelectorImpl>::LocalName) + -> &'a <E::Impl as SelectorImpl>::LocalName where E: Element { - let name = if element.is_html_element_in_html_document() { - &attr.lower_name + if element.is_html_element_in_html_document() { + local_name_lower } else { - &attr.name - }; - (&attr.namespace, name) + local_name + } } #[inline] diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 96081a50b2b..befbfd084cc 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use arcslice::ArcSlice; -use attr::{CaseSensitivity, SELECTOR_WHITESPACE}; +use attr::{AttrSelectorWithNamespace, AttrSelectorOperation, AttrSelectorOperator}; +use attr::{CaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint}; use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter}; use precomputed_hash::PrecomputedHash; use smallvec::SmallVec; @@ -313,18 +314,28 @@ impl<Impl: SelectorImpl> SelectorMethods for Component<Impl> { return false; } } - }, - AttrExists(ref selector) | - AttrEqual(ref selector, _, _) | - AttrIncludes(ref selector, _) | - AttrDashMatch(ref selector, _) | - AttrPrefixMatch(ref selector, _) | - AttrSubstringMatch(ref selector, _) | - AttrSuffixMatch(ref selector, _) => { - if !visitor.visit_attribute_selector(selector) { + } + + AttributeInNoNamespace { ref local_name, ref local_name_lower, .. } | + AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => { + if !visitor.visit_attribute_selector( + &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()), + local_name, + local_name_lower, + ) { + return false; + } + } + AttributeOther(ref attr_selector) => { + if !visitor.visit_attribute_selector( + &attr_selector.namespace(), + &attr_selector.local_name, + &attr_selector.local_name_lower, + ) { return false; } } + NonTSPseudoClass(ref pseudo_class) => { if !pseudo_class.visit(visitor) { return false; @@ -337,6 +348,11 @@ impl<Impl: SelectorImpl> SelectorMethods for Component<Impl> { } } +pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl { + // Rust type’s default, not default namespace + Impl::NamespaceUrl::default() +} + /// A ComplexSelectors stores a sequence of simple selectors and combinators. The /// iterator classes allow callers to iterate at either the raw sequence level or /// at the level of sequences of simple selectors separated by combinators. Most @@ -523,19 +539,20 @@ pub enum Component<Impl: SelectorImpl> { ID(Impl::Identifier), Class(Impl::ClassName), - // Attribute selectors - AttrExists(AttrSelector<Impl>), // [foo] - AttrEqual(AttrSelector<Impl>, Impl::AttrValue, CaseSensitivity), // [foo=bar] - AttrIncludes(AttrSelector<Impl>, Impl::AttrValue), // [foo~=bar] - AttrDashMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo|=bar] - AttrPrefixMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo^=bar] - AttrSubstringMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo*=bar] - AttrSuffixMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo$=bar] - - AttrIncludesNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value or with whitespace - AttrPrefixNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value - AttrSubstringNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value - AttrSuffixNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value + AttributeInNoNamespaceExists { + local_name: Impl::LocalName, + local_name_lower: Impl::LocalName, + }, + AttributeInNoNamespace { + local_name: Impl::LocalName, + local_name_lower: Impl::LocalName, + operator: AttrSelectorOperator, + value: Impl::AttrValue, + case_sensitivity: CaseSensitivity, + never_matches: bool, + }, + // Use a Box in the less common cases with more data to keep size_of::<Component>() small. + AttributeOther(Box<AttrSelectorWithNamespace<Impl>>), // Pseudo-classes // @@ -610,35 +627,6 @@ pub struct LocalName<Impl: SelectorImpl> { pub lower_name: Impl::LocalName, } -#[derive(Eq, PartialEq, Clone)] -pub struct AttrSelector<Impl: SelectorImpl> { - pub name: Impl::LocalName, - pub lower_name: Impl::LocalName, - pub namespace: NamespaceConstraint<Impl>, -} - -#[derive(Eq, PartialEq, Clone, Debug)] -pub enum NamespaceConstraint<Impl: SelectorImpl> { - Any, - Specific(Namespace<Impl>), -} - -#[derive(Eq, PartialEq, Clone)] -pub struct Namespace<Impl: SelectorImpl> { - pub prefix: Option<Impl::NamespacePrefix>, - pub url: Impl::NamespaceUrl, -} - -impl<Impl: SelectorImpl> Default for Namespace<Impl> { - fn default() -> Self { - Namespace { - prefix: None, - url: Impl::NamespaceUrl::default(), // empty string - } - } -} - - impl<Impl: SelectorImpl> Debug for Selector<Impl> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("Selector(")?; @@ -656,10 +644,7 @@ impl<Impl: SelectorImpl> Debug for ComplexSelector<Impl> { impl<Impl: SelectorImpl> Debug for Component<Impl> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) } } -impl<Impl: SelectorImpl> Debug for AttrSelector<Impl> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) } -} -impl<Impl: SelectorImpl> Debug for Namespace<Impl> { +impl<Impl: SelectorImpl> Debug for AttrSelectorWithNamespace<Impl> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) } } impl<Impl: SelectorImpl> Debug for LocalName<Impl> { @@ -737,27 +722,25 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> { dest.write_char('|') } - // Attribute selectors - AttrExists(ref a) => { + AttributeInNoNamespaceExists { ref local_name, .. } => { dest.write_char('[')?; - a.to_css(dest)?; + display_to_css_identifier(local_name, dest)?; dest.write_char(']') } - AttrEqual(ref a, ref v, case) => { - attr_selector_to_css(a, " = ", v, match case { - CaseSensitivity::CaseSensitive => None, - CaseSensitivity::AsciiCaseInsensitive => Some(" i"), - }, dest) + AttributeInNoNamespace { ref local_name, operator, ref value, case_sensitivity, .. } => { + dest.write_char('[')?; + display_to_css_identifier(local_name, dest)?; + operator.to_css(dest)?; + dest.write_char('"')?; + write!(CssStringWriter::new(dest), "{}", value)?; + dest.write_char('"')?; + match case_sensitivity { + CaseSensitivity::CaseSensitive => {}, + CaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?, + } + dest.write_char(']') } - AttrDashMatch(ref a, ref v) => attr_selector_to_css(a, " |= ", v, None, dest), - AttrIncludesNeverMatch(ref a, ref v) | - AttrIncludes(ref a, ref v) => attr_selector_to_css(a, " ~= ", v, None, dest), - AttrPrefixNeverMatch(ref a, ref v) | - AttrPrefixMatch(ref a, ref v) => attr_selector_to_css(a, " ^= ", v, None, dest), - AttrSubstringNeverMatch(ref a, ref v) | - AttrSubstringMatch(ref a, ref v) => attr_selector_to_css(a, " *= ", v, None, dest), - AttrSuffixNeverMatch(ref a, ref v) | - AttrSuffixMatch(ref a, ref v) => attr_selector_to_css(a, " $= ", v, None, dest), + AttributeOther(ref attr_selector) => attr_selector.to_css(dest), // Pseudo-classes Negation(ref arg) => { @@ -786,22 +769,33 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> { } } -impl<Impl: SelectorImpl> ToCss for AttrSelector<Impl> { +impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if let NamespaceConstraint::Specific(ref ns) = self.namespace { - ns.to_css(dest)?; + dest.write_char('[')?; + match self.namespace { + NamespaceConstraint::Specific((ref prefix, _)) => { + display_to_css_identifier(prefix, dest)?; + dest.write_char('|')? + } + NamespaceConstraint::Any => { + dest.write_str("*|")? + } } - display_to_css_identifier(&self.name, dest) - } -} - -impl<Impl: SelectorImpl> ToCss for Namespace<Impl> { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if let Some(ref prefix) = self.prefix { - display_to_css_identifier(prefix, dest)?; - dest.write_char('|')?; + display_to_css_identifier(&self.local_name, dest)?; + match self.operation { + AttrSelectorOperation::Exists => {}, + AttrSelectorOperation::WithValue { operator, case_sensitivity, ref expected_value } => { + operator.to_css(dest)?; + dest.write_char('"')?; + write!(CssStringWriter::new(dest), "{}", expected_value)?; + dest.write_char('"')?; + match case_sensitivity { + CaseSensitivity::CaseSensitive => {}, + CaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?, + } + }, } - Ok(()) + dest.write_char(']') } } @@ -811,26 +805,6 @@ impl<Impl: SelectorImpl> ToCss for LocalName<Impl> { } } -fn attr_selector_to_css<Impl, W>(attr: &AttrSelector<Impl>, - operator: &str, - value: &Impl::AttrValue, - modifier: Option<&str>, - dest: &mut W) - -> fmt::Result -where Impl: SelectorImpl, W: fmt::Write -{ - dest.write_char('[')?; - attr.to_css(dest)?; - dest.write_str(operator)?; - dest.write_char('"')?; - write!(CssStringWriter::new(dest), "{}", value)?; - dest.write_char('"')?; - if let Some(m) = modifier { - dest.write_str(m)?; - } - dest.write_char(']') -} - /// Serialize the output of Display as a CSS identifier fn display_to_css_identifier<T: Display, W: fmt::Write>(x: &T, dest: &mut W) -> fmt::Result { // FIXME(SimonSapin): it is possible to avoid this heap allocation @@ -926,18 +900,9 @@ fn complex_selector_specificity<Impl>(selector: &ComplexSelector<Impl>) specificity.id_selectors += 1 } Component::Class(..) | - Component::AttrExists(..) | - Component::AttrEqual(..) | - Component::AttrIncludes(..) | - Component::AttrDashMatch(..) | - Component::AttrPrefixMatch(..) | - Component::AttrSubstringMatch(..) | - Component::AttrSuffixMatch(..) | - - Component::AttrIncludesNeverMatch(..) | - Component::AttrPrefixNeverMatch(..) | - Component::AttrSubstringNeverMatch(..) | - Component::AttrSuffixNeverMatch(..) | + Component::AttributeInNoNamespace { .. } | + Component::AttributeInNoNamespaceExists { .. } | + Component::AttributeOther(..) | Component::FirstChild | Component::LastChild | Component::OnlyChild | Component::Root | @@ -1223,89 +1188,118 @@ fn parse_attribute_selector<P, Impl>(parser: &P, input: &mut CssParser) -> Result<Component<Impl>, ()> where P: Parser<Impl=Impl>, Impl: SelectorImpl { - let attr = match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { + let namespace; + let local_name; + let local_name_lower; + match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { None => return Err(()), Some((_, None)) => unreachable!(), - Some((namespace, Some(local_name))) => AttrSelector { - namespace: match namespace { + Some((ns, Some(ln))) => { + local_name_lower = from_ascii_lowercase(&ln); + local_name = from_cow_str(ln); + namespace = match ns { QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => { - NamespaceConstraint::Specific(Namespace { - prefix: None, - url: Impl::NamespaceUrl::default(), - }) + None } QNamePrefix::ExplicitNamespace(prefix, url) => { - NamespaceConstraint::Specific(Namespace { - prefix: Some(prefix), - url: url, - }) + Some(NamespaceConstraint::Specific((prefix, url))) } QNamePrefix::ExplicitAnyNamespace => { - NamespaceConstraint::Any + Some(NamespaceConstraint::Any) } QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => { unreachable!() // Not returned with in_attr_selector = true } - }, - lower_name: from_ascii_lowercase(&local_name), - name: from_cow_str(local_name), - }, - }; + } + } + } + let operator; + let value; + let never_matches; match input.next() { // [foo] - Err(()) => Ok(Component::AttrExists(attr)), + Err(()) => { + if let Some(namespace) = namespace { + return Ok(Component::AttributeOther(Box::new(AttrSelectorWithNamespace { + namespace: namespace, + local_name: local_name, + local_name_lower: local_name_lower, + operation: AttrSelectorOperation::Exists, + never_matches: false, + }))) + } else { + return Ok(Component::AttributeInNoNamespaceExists { + local_name: local_name, + local_name_lower: local_name_lower, + }) + } + } // [foo=bar] Ok(Token::Delim('=')) => { - let value = input.expect_ident_or_string()?; - let flags = parse_attribute_flags(input)?; - Ok(Component::AttrEqual(attr, from_cow_str(value), flags)) + value = input.expect_ident_or_string()?; + never_matches = false; + operator = AttrSelectorOperator::Equal; } // [foo~=bar] Ok(Token::IncludeMatch) => { - let value = input.expect_ident_or_string()?; - if value.is_empty() || value.contains(SELECTOR_WHITESPACE) { - Ok(Component::AttrIncludesNeverMatch(attr, from_cow_str(value))) - } else { - Ok(Component::AttrIncludes(attr, from_cow_str(value))) - } + value = input.expect_ident_or_string()?; + never_matches = value.is_empty() || value.contains(SELECTOR_WHITESPACE); + operator = AttrSelectorOperator::Includes; } // [foo|=bar] Ok(Token::DashMatch) => { - let value = input.expect_ident_or_string()?; - Ok(Component::AttrDashMatch(attr, from_cow_str(value))) + value = input.expect_ident_or_string()?; + never_matches = false; + operator = AttrSelectorOperator::DashMatch; } // [foo^=bar] Ok(Token::PrefixMatch) => { - let value = input.expect_ident_or_string()?; - if value.is_empty() { - Ok(Component::AttrPrefixNeverMatch(attr, from_cow_str(value))) - } else { - Ok(Component::AttrPrefixMatch(attr, from_cow_str(value))) - } + value = input.expect_ident_or_string()?; + never_matches = value.is_empty(); + operator = AttrSelectorOperator::Prefix; } // [foo*=bar] Ok(Token::SubstringMatch) => { - let value = input.expect_ident_or_string()?; - if value.is_empty() { - Ok(Component::AttrSubstringNeverMatch(attr, from_cow_str(value))) - } else { - Ok(Component::AttrSubstringMatch(attr, from_cow_str(value))) - } + value = input.expect_ident_or_string()?; + never_matches = value.is_empty(); + operator = AttrSelectorOperator::Substring; } // [foo$=bar] Ok(Token::SuffixMatch) => { - let value = input.expect_ident_or_string()?; - if value.is_empty() { - Ok(Component::AttrSuffixNeverMatch(attr, from_cow_str(value))) - } else { - Ok(Component::AttrSuffixMatch(attr, from_cow_str(value))) + value = input.expect_ident_or_string()?; + never_matches = value.is_empty(); + operator = AttrSelectorOperator::Suffix; + } + _ => return Err(()) + } + + let case_sensitivity = parse_attribute_flags(input)?; + let value = from_cow_str(value); + if let Some(namespace) = namespace { + Ok(Component::AttributeOther(Box::new(AttrSelectorWithNamespace { + namespace: namespace, + local_name: local_name, + local_name_lower: local_name_lower, + never_matches: never_matches, + operation: AttrSelectorOperation::WithValue { + operator: operator, + case_sensitivity: case_sensitivity, + expected_value: value, } - } - _ => Err(()) + }))) + } else { + Ok(Component::AttributeInNoNamespace { + local_name: local_name, + local_name_lower: local_name_lower, + operator: operator, + value: value, + case_sensitivity: case_sensitivity, + never_matches: never_matches, + }) } } @@ -1845,14 +1839,12 @@ pub mod tests { // https://github.com/mozilla/servo/pull/1652 let mut parser = DummyParser::default(); assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList(vec!(Selector { - inner: SelectorInner::from_vec(vec!( - Component::AttrExists(AttrSelector { - name: DummyAtom::from("Foo"), - lower_name: DummyAtom::from("foo"), - namespace: NamespaceConstraint::Specific(Namespace { - prefix: None, - url: "".into(), - }) }))), + inner: SelectorInner::from_vec(vec![ + Component::AttributeInNoNamespaceExists { + local_name: DummyAtom::from("Foo"), + local_name_lower: DummyAtom::from("foo"), + } + ]), specificity_and_flags: specificity(0, 1, 0), })))); assert_eq!(parse_ns("svg|circle", &parser), Err(())); @@ -1885,14 +1877,10 @@ pub mod tests { inner: SelectorInner::from_vec( vec![ Component::DefaultNamespace(MATHML.into()), - Component::AttrExists(AttrSelector { - name: DummyAtom::from("Foo"), - lower_name: DummyAtom::from("foo"), - namespace: NamespaceConstraint::Specific(Namespace { - prefix: None, - url: "".into(), - }), - }), + Component::AttributeInNoNamespaceExists { + local_name: DummyAtom::from("Foo"), + local_name_lower: DummyAtom::from("foo"), + }, ]), specificity_and_flags: specificity(0, 1, 0), })))); @@ -1960,14 +1948,14 @@ pub mod tests { assert_eq!(parse("[attr |= \"foo\"]"), Ok(SelectorList(vec![Selector { inner: SelectorInner::from_vec( vec![ - Component::AttrDashMatch(AttrSelector { - name: DummyAtom::from("attr"), - lower_name: DummyAtom::from("attr"), - namespace: NamespaceConstraint::Specific(Namespace { - prefix: None, - url: "".into(), - }), - }, DummyAtom::from("foo")) + Component::AttributeInNoNamespace { + local_name: DummyAtom::from("attr"), + local_name_lower: DummyAtom::from("attr"), + operator: AttrSelectorOperator::DashMatch, + value: DummyAtom::from("foo"), + never_matches: false, + case_sensitivity: CaseSensitivity::CaseSensitive, + } ]), specificity_and_flags: specificity(0, 1, 0), }]))); diff --git a/components/selectors/size_of_tests.rs b/components/selectors/size_of_tests.rs index c03a0c80db5..5fec3085fcb 100644 --- a/components/selectors/size_of_tests.rs +++ b/components/selectors/size_of_tests.rs @@ -16,8 +16,7 @@ size_of_test!(size_of_pseudo_element, gecko_like_types::PseudoElement, 1); size_of_test!(size_of_selector_inner, SelectorInner<Impl>, 40); size_of_test!(size_of_complex_selector, ComplexSelector<Impl>, 24); -size_of_test!(size_of_component, Component<Impl>, 64); -size_of_test!(size_of_attr_selector, AttrSelector<Impl>, 48); +size_of_test!(size_of_component, Component<Impl>, 32); size_of_test!(size_of_pseudo_class, PseudoClass, 24); impl parser::PseudoElement for gecko_like_types::PseudoElement { diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index 42659bfc615..689d5c2359c 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -5,9 +5,9 @@ //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and //! style. -use attr::AttrSelectorOperation; +use attr::{AttrSelectorOperation, NamespaceConstraint}; use matching::{ElementSelectorFlags, MatchingContext}; -use parser::{NamespaceConstraint, SelectorImpl}; +use parser::SelectorImpl; pub trait Element: Sized { type Impl: SelectorImpl; @@ -22,26 +22,29 @@ pub trait Element: Sized { self.parent_element() } - // Skips non-element nodes + /// Skips non-element nodes fn first_child_element(&self) -> Option<Self>; - // Skips non-element nodes + /// Skips non-element nodes fn last_child_element(&self) -> Option<Self>; - // Skips non-element nodes + /// Skips non-element nodes fn prev_sibling_element(&self) -> Option<Self>; - // Skips non-element nodes + /// Skips non-element nodes fn next_sibling_element(&self) -> Option<Self>; fn is_html_element_in_html_document(&self) -> bool; + fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName; + + /// Empty string for no namespace fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl; fn attr_matches(&self, - ns: &NamespaceConstraint<Self::Impl>, + ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>, local_name: &<Self::Impl as SelectorImpl>::LocalName, - operation: &AttrSelectorOperation<Self::Impl>) + operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>) -> bool; fn match_non_ts_pseudo_class<F>(&self, @@ -56,6 +59,7 @@ pub trait Element: Sized { -> bool; fn get_id(&self) -> Option<<Self::Impl as SelectorImpl>::Identifier>; + fn has_class(&self, name: &<Self::Impl as SelectorImpl>::ClassName) -> bool; /// Returns whether this element matches `:empty`. diff --git a/components/selectors/visitor.rs b/components/selectors/visitor.rs index be335aed87b..07f121fe82f 100644 --- a/components/selectors/visitor.rs +++ b/components/selectors/visitor.rs @@ -6,8 +6,8 @@ #![deny(missing_docs)] -use parser::{AttrSelector, Combinator, Component}; -use parser::{SelectorImpl, SelectorIter}; +use attr::NamespaceConstraint; +use parser::{Combinator, Component, SelectorImpl, SelectorIter}; /// A trait to visit selector properties. /// @@ -20,7 +20,12 @@ pub trait SelectorVisitor { /// Visit an attribute selector that may match (there are other selectors /// that may never match, like those containing whitespace or the empty /// string). - fn visit_attribute_selector(&mut self, _: &AttrSelector<Self::Impl>) -> bool { + fn visit_attribute_selector( + &mut self, + _namespace: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>, + _local_name: &<Self::Impl as SelectorImpl>::LocalName, + _local_name_lower: &<Self::Impl as SelectorImpl>::LocalName, + ) -> bool { true } diff --git a/components/style/attr.rs b/components/style/attr.rs index e3df55f3d09..d1e97703e5e 100644 --- a/components/style/attr.rs +++ b/components/style/attr.rs @@ -12,7 +12,6 @@ use cssparser::{self, Color, RGBA}; use euclid::num::Zero; use num_traits::ToPrimitive; use properties::PropertyDeclarationBlock; -use selector_parser::SelectorImpl; use selectors::attr::AttrSelectorOperation; use servo_url::ServoUrl; use shared_lock::Locked; @@ -352,9 +351,10 @@ impl AttrValue { } } - pub fn eval_selector(&self, selector: &AttrSelectorOperation<SelectorImpl>) -> bool { + pub fn eval_selector(&self, selector: &AttrSelectorOperation<&String>) -> bool { // FIXME(SimonSapin) this can be more efficient by matching on `(self, selector)` variants - // and doing Atom comparisons instead of string comparisons where possible. + // and doing Atom comparisons instead of string comparisons where possible, + // with SelectorImpl::AttrValue changed to Atom. selector.eval_str(self) } } diff --git a/components/style/gecko/snapshot.rs b/components/style/gecko/snapshot.rs index 33abdcc5bd9..3bc1a946c5e 100644 --- a/components/style/gecko/snapshot.rs +++ b/components/style/gecko/snapshot.rs @@ -14,10 +14,8 @@ use gecko_bindings::structs::ServoElementSnapshot; use gecko_bindings::structs::ServoElementSnapshotFlags as Flags; use gecko_bindings::structs::ServoElementSnapshotTable; use restyle_hints::ElementSnapshot; -use selector_parser::SelectorImpl; -use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity}; -use selectors::parser::NamespaceConstraint; -use string_cache::Atom; +use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint}; +use string_cache::{Atom, Namespace}; /// A snapshot of a Gecko element. pub type GeckoElementSnapshot = ServoElementSnapshot; @@ -59,9 +57,9 @@ impl GeckoElementSnapshot { /// selectors::Element::attr_matches pub fn attr_matches(&self, - ns: &NamespaceConstraint<SelectorImpl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &Atom, - operation: &AttrSelectorOperation<SelectorImpl>) + operation: &AttrSelectorOperation<&Atom>) -> bool { unsafe { match *operation { diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index ac4452a0e03..5801101eacf 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -64,9 +64,8 @@ use properties::style_structs::Font; use rule_tree::CascadeLevel as ServoCascadeLevel; use selector_parser::ElementExt; use selectors::Element; -use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity}; +use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint}; use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode}; -use selectors::parser::NamespaceConstraint; use shared_lock::Locked; use sink::Push; use std::cell::RefCell; @@ -1140,9 +1139,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } fn attr_matches(&self, - ns: &NamespaceConstraint<SelectorImpl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &Atom, - operation: &AttrSelectorOperation<SelectorImpl>) + operation: &AttrSelectorOperation<&Atom>) -> bool { unsafe { match *operation { @@ -1413,11 +1412,11 @@ pub trait NamespaceConstraintHelpers { fn atom_or_null(&self) -> *mut nsIAtom; } -impl NamespaceConstraintHelpers for NamespaceConstraint<SelectorImpl> { +impl<'a> NamespaceConstraintHelpers for NamespaceConstraint<&'a Namespace> { fn atom_or_null(&self) -> *mut nsIAtom { match *self { NamespaceConstraint::Any => ptr::null_mut(), - NamespaceConstraint::Specific(ref ns) => ns.url.0.as_ptr(), + NamespaceConstraint::Specific(ref ns) => ns.0.as_ptr(), } } } diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index d5e2564d3de..f1e33462c37 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -8,19 +8,19 @@ use Atom; use LocalName; +use Namespace; use dom::TElement; use element_state::*; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsRestyleHint; #[cfg(feature = "servo")] use heapsize::HeapSizeOf; -use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap}; +use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue}; use selectors::Element; -use selectors::attr::AttrSelectorOperation; +use selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode}; use selectors::matching::matches_selector; -use selectors::parser::{Combinator, Component, Selector}; -use selectors::parser::{SelectorInner, SelectorMethods, NamespaceConstraint}; +use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorMethods}; use selectors::visitor::SelectorVisitor; use smallvec::SmallVec; use std::borrow::Borrow; @@ -371,9 +371,9 @@ impl<'a, E> Element for ElementWrapper<'a, E> } fn attr_matches(&self, - ns: &NamespaceConstraint<Self::Impl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &LocalName, - operation: &AttrSelectorOperation<Self::Impl>) + operation: &AttrSelectorOperation<&AttrValue>) -> bool { match self.snapshot() { Some(snapshot) if snapshot.has_attrs() => { @@ -437,13 +437,9 @@ fn is_attr_selector(sel: &Component<SelectorImpl>) -> bool { match *sel { Component::ID(_) | Component::Class(_) | - Component::AttrExists(_) | - Component::AttrEqual(_, _, _) | - Component::AttrIncludes(_, _) | - Component::AttrDashMatch(_, _) | - Component::AttrPrefixMatch(_, _) | - Component::AttrSubstringMatch(_, _) | - Component::AttrSuffixMatch(_, _) => true, + Component::AttributeInNoNamespaceExists { .. } | + Component::AttributeInNoNamespace { .. } | + Component::AttributeOther(_) => true, _ => false, } } diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index f86a9f16469..c5eb67b6a5a 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -14,10 +14,10 @@ use element_state::ElementState; use fnv::FnvHashMap; use restyle_hints::ElementSnapshot; use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser}; -use selectors::{Element}; -use selectors::attr::AttrSelectorOperation; +use selectors::Element; +use selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; use selectors::matching::{MatchingContext, MatchingMode}; -use selectors::parser::{SelectorMethods, NamespaceConstraint}; +use selectors::parser::SelectorMethods; use selectors::visitor::SelectorVisitor; use std::borrow::Cow; use std::fmt; @@ -559,14 +559,13 @@ impl ElementSnapshot for ServoElementSnapshot { impl ServoElementSnapshot { /// selectors::Element::attr_matches pub fn attr_matches(&self, - ns: &NamespaceConstraint<SelectorImpl>, + ns: &NamespaceConstraint<&Namespace>, local_name: &LocalName, - operation: &AttrSelectorOperation<SelectorImpl>) + operation: &AttrSelectorOperation<&String>) -> bool { - use selectors::parser::NamespaceConstraint; match *ns { NamespaceConstraint::Specific(ref ns) => { - self.get_attr(&ns.url, local_name) + self.get_attr(ns, local_name) .map_or(false, |value| value.eval_selector(operation)) } NamespaceConstraint::Any => { diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 644552050b2..a5c103c5a55 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -6,7 +6,7 @@ #![deny(missing_docs)] -use {Atom, LocalName}; +use {Atom, LocalName, Namespace}; use bit_vec::BitVec; use context::QuirksMode; use data::ComputedStyle; @@ -26,10 +26,11 @@ use properties::PropertyDeclarationBlock; use restyle_hints::{RestyleHint, DependencySet}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; use selector_parser::{SelectorImpl, PseudoElement, SnapshotMap}; +use selectors::attr::NamespaceConstraint; use selectors::bloom::BloomFilter; use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS}; use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode}; -use selectors::parser::{AttrSelector, Combinator, Component, Selector, SelectorInner, SelectorIter}; +use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorIter}; use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector}; use selectors::visitor::SelectorVisitor; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; @@ -502,7 +503,7 @@ impl Stylist { /// Returns whether the given attribute might appear in an attribute /// selector of some rule in the stylist. pub fn might_have_attribute_dependency(&self, - local_name: &<SelectorImpl as ::selectors::SelectorImpl>::LocalName) + local_name: &LocalName) -> bool { #[cfg(feature = "servo")] let style_lower_name = local_name!("style"); @@ -1088,17 +1089,19 @@ struct AttributeAndStateDependencyVisitor<'a>(&'a mut Stylist); impl<'a> SelectorVisitor for AttributeAndStateDependencyVisitor<'a> { type Impl = SelectorImpl; - fn visit_attribute_selector(&mut self, selector: &AttrSelector<Self::Impl>) -> bool { + fn visit_attribute_selector(&mut self, _ns: &NamespaceConstraint<&Namespace>, + name: &LocalName, lower_name: &LocalName) + -> bool { #[cfg(feature = "servo")] let style_lower_name = local_name!("style"); #[cfg(feature = "gecko")] let style_lower_name = atom!("style"); - if selector.lower_name == style_lower_name { + if *lower_name == style_lower_name { self.0.style_attribute_dependency = true; } else { - self.0.attribute_dependencies.insert(&selector.name); - self.0.attribute_dependencies.insert(&selector.lower_name); + self.0.attribute_dependencies.insert(&name); + self.0.attribute_dependencies.insert(&lower_name); } true } @@ -1157,13 +1160,9 @@ impl SelectorVisitor for RevalidationVisitor { /// concerned. fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool { match *s { - Component::AttrExists(_) | - Component::AttrEqual(_, _, _) | - Component::AttrIncludes(_, _) | - Component::AttrDashMatch(_, _) | - Component::AttrPrefixMatch(_, _) | - Component::AttrSubstringMatch(_, _) | - Component::AttrSuffixMatch(_, _) | + Component::AttributeInNoNamespaceExists { .. } | + Component::AttributeInNoNamespace { .. } | + Component::AttributeOther(_) | Component::Empty | Component::FirstChild | Component::LastChild | diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 52030bc21ac..168268b7ba2 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -6,7 +6,7 @@ use cssparser::{self, Parser as CssParser, SourcePosition, SourceLocation}; use html5ever::{Namespace as NsAtom}; use media_queries::CSSErrorReporterTest; use parking_lot::RwLock; -use selectors::attr::CaseSensitivity; +use selectors::attr::*; use selectors::parser::*; use servo_atoms::Atom; use servo_url::ServoUrl; @@ -98,14 +98,14 @@ fn test_parse_stylesheet() { name: local_name!("input"), lower_name: local_name!("input"), }), - Component::AttrEqual(AttrSelector { - name: local_name!("type"), - lower_name: local_name!("type"), - namespace: NamespaceConstraint::Specific(Namespace { - prefix: None, - url: ns!() - }), - }, "hidden".to_owned(), CaseSensitivity::AsciiCaseInsensitive) + Component::AttributeInNoNamespace { + local_name: local_name!("type"), + local_name_lower: local_name!("type"), + operator: AttrSelectorOperator::Equal, + value: "hidden".to_owned(), + case_sensitivity: CaseSensitivity::AsciiCaseInsensitive, + never_matches: false, + } ]), (0 << 20) + (1 << 10) + (1 << 0) ), |