mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
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:
parent
eba573d774
commit
f879ebcc99
3 changed files with 24 additions and 15 deletions
|
@ -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,
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue