selectors: Don't track class and id ancestor hashes in quirks mode.

It's incorrect to track classes and id selectors in a quirks-mode document,
since they should match case-insensitively.

Bug: 1382812
Reviewed-by: bholley
MozReview-Commit-ID: 4uvrfYsWb1v
This commit is contained in:
Emilio Cobos Álvarez 2017-07-20 22:10:22 +02:00
parent eba573d774
commit f879ebcc99
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 24 additions and 15 deletions

View file

@ -6,6 +6,7 @@ use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorO
use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint}; use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint};
use bloom::BLOOM_HASH_MASK; use bloom::BLOOM_HASH_MASK;
use builder::{SelectorBuilder, SpecificityAndFlags}; use builder::{SelectorBuilder, SpecificityAndFlags};
use context::QuirksMode;
use cssparser::{ParseError, BasicParseError, CompactCowStr}; use cssparser::{ParseError, BasicParseError, CompactCowStr};
use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter}; use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter};
use precomputed_hash::PrecomputedHash; use precomputed_hash::PrecomputedHash;
@ -218,17 +219,21 @@ pub struct AncestorHashes {
} }
impl AncestorHashes { impl AncestorHashes {
pub fn new<Impl: SelectorImpl>(s: &Selector<Impl>) -> Self { pub fn new<Impl: SelectorImpl>(
Self::from_iter(s.iter()) selector: &Selector<Impl>,
quirks_mode: QuirksMode,
) -> Self {
Self::from_iter(selector.iter(), quirks_mode)
} }
pub fn from_iter<Impl: SelectorImpl>(iter: SelectorIter<Impl>) -> Self { fn from_iter<Impl: SelectorImpl>(
iter: SelectorIter<Impl>,
quirks_mode: QuirksMode,
) -> Self {
// Compute ancestor hashes for the bloom filter. // Compute ancestor hashes for the bloom filter.
let mut hashes = [0u32; 4]; let mut hashes = [0u32; 4];
let mut hash_iter = AncestorIter::new(iter) let mut hash_iter = AncestorIter::new(iter)
.map(|x| x.ancestor_hash()) .filter_map(|x| x.ancestor_hash(quirks_mode));
.filter(|x| x.is_some())
.map(|x| x.unwrap());
for i in 0..4 { for i in 0..4 {
hashes[i] = match hash_iter.next() { hashes[i] = match hash_iter.next() {
Some(x) => x & BLOOM_HASH_MASK, Some(x) => x & BLOOM_HASH_MASK,
@ -532,7 +537,7 @@ impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
} }
/// An iterator over all simple selectors belonging to ancestors. /// An iterator over all simple selectors belonging to ancestors.
pub struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>); struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> { impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
/// Creates an AncestorIter. The passed-in iterator is assumed to point to /// Creates an AncestorIter. The passed-in iterator is assumed to point to
/// the beginning of the child sequence, which will be skipped. /// the beginning of the child sequence, which will be skipped.
@ -672,12 +677,12 @@ pub enum Component<Impl: SelectorImpl> {
impl<Impl: SelectorImpl> Component<Impl> { impl<Impl: SelectorImpl> Component<Impl> {
/// Compute the ancestor hash to check against the bloom filter. /// Compute the ancestor hash to check against the bloom filter.
pub fn ancestor_hash(&self) -> Option<u32> { fn ancestor_hash(&self, quirks_mode: QuirksMode) -> Option<u32> {
match *self { match *self {
Component::LocalName(LocalName { ref name, ref lower_name }) => { Component::LocalName(LocalName { ref name, ref lower_name }) => {
// Only insert the local-name into the filter if it's all lowercase. // Only insert the local-name into the filter if it's all
// Otherwise we would need to test both hashes, and our data structures // lowercase. Otherwise we would need to test both hashes, and
// aren't really set up for that. // our data structures aren't really set up for that.
if name == lower_name { if name == lower_name {
Some(name.precomputed_hash()) Some(name.precomputed_hash())
} else { } else {
@ -688,10 +693,12 @@ impl<Impl: SelectorImpl> Component<Impl> {
Component::Namespace(_, ref url) => { Component::Namespace(_, ref url) => {
Some(url.precomputed_hash()) Some(url.precomputed_hash())
}, },
Component::ID(ref id) => { // In quirks mode, class and id selectors should match
// case-insensitively, so just avoid inserting them into the filter.
Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => {
Some(id.precomputed_hash()) Some(id.precomputed_hash())
}, },
Component::Class(ref class) => { Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
Some(class.precomputed_hash()) Some(class.precomputed_hash())
}, },
_ => None, _ => None,

View file

@ -490,7 +490,9 @@ impl Stylist {
self.element_map.borrow_for_origin(&origin) self.element_map.borrow_for_origin(&origin)
}; };
let hashes = AncestorHashes::new(&selector); let hashes =
AncestorHashes::new(&selector, self.quirks_mode);
map.insert( map.insert(
Rule::new(selector.clone(), Rule::new(selector.clone(),
hashes.clone(), hashes.clone(),

View file

@ -45,7 +45,7 @@ fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
let guard = shared_lock.read(); let guard = shared_lock.read();
let rule = locked.read_with(&guard); let rule = locked.read_with(&guard);
rule.selectors.0.iter().map(|s| { rule.selectors.0.iter().map(|s| {
Rule::new(s.clone(), AncestorHashes::new(s), locked.clone(), i as u32) Rule::new(s.clone(), AncestorHashes::new(s, QuirksMode::NoQuirks), locked.clone(), i as u32)
}).collect() }).collect()
}).collect(), shared_lock) }).collect(), shared_lock)
} }