mirror of
https://github.com/servo/servo.git
synced 2025-06-21 07:38:59 +01:00
Auto merge of #16549 - bholley:inline_selectors, r=emilio
store simple selectors and combinators inline https://bugzilla.mozilla.org/show_bug.cgi?id=1357973 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16549) <!-- Reviewable:end -->
This commit is contained in:
commit
f44e3cdae2
11 changed files with 866 additions and 486 deletions
326
components/selectors/arcslice.rs
Normal file
326
components/selectors/arcslice.rs
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
/* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*
|
||||||
|
* See the COPYRIGHT file at the top-level directory of this distribution */
|
||||||
|
//! A thread-safe reference-counted slice type.
|
||||||
|
//!
|
||||||
|
//! Forked from https://github.com/huonw/shared_slice , which doesn't work on
|
||||||
|
//! rust stable.
|
||||||
|
|
||||||
|
use std::{cmp, fmt, ops};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
|
|
||||||
|
/// A reference-counted slice type.
|
||||||
|
pub struct ArcSlice<T> {
|
||||||
|
data: *const [T],
|
||||||
|
counts: Arc<Box<[T]>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send + Sync> Send for ArcSlice<T> {}
|
||||||
|
unsafe impl<T: Send + Sync> Sync for ArcSlice<T> {}
|
||||||
|
|
||||||
|
/// A non-owning reference-counted slice type.
|
||||||
|
///
|
||||||
|
/// This is to `ArcSlice` as `std::sync::Weak` is to `std::sync::Arc`, and
|
||||||
|
/// allows one to have cyclic references without stopping memory from
|
||||||
|
/// being deallocated.
|
||||||
|
pub struct WeakSlice<T> {
|
||||||
|
data: *const [T],
|
||||||
|
counts: Weak<Box<[T]>>,
|
||||||
|
}
|
||||||
|
unsafe impl<T: Send + Sync> Send for WeakSlice<T> {}
|
||||||
|
unsafe impl<T: Send + Sync> Sync for WeakSlice<T> {}
|
||||||
|
|
||||||
|
impl<T> ArcSlice<T> {
|
||||||
|
/// Construct a new `ArcSlice` containing the elements of `slice`.
|
||||||
|
///
|
||||||
|
/// This reuses the allocation of `slice`.
|
||||||
|
pub fn new(slice: Box<[T]>) -> ArcSlice<T> {
|
||||||
|
ArcSlice {
|
||||||
|
data: &*slice,
|
||||||
|
counts: Arc::new(slice),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Downgrade self into a weak slice.
|
||||||
|
pub fn downgrade(&self) -> WeakSlice<T> {
|
||||||
|
WeakSlice {
|
||||||
|
data: self.data,
|
||||||
|
counts: Arc::downgrade(&self.counts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a new `ArcSlice` that only points to elements at
|
||||||
|
/// indices `lo` (inclusive) through `hi` (exclusive).
|
||||||
|
///
|
||||||
|
/// This consumes `self` to avoid unnecessary reference-count
|
||||||
|
/// modifications. Use `.clone()` if it is necessary to refer to
|
||||||
|
/// `self` after calling this.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `lo > hi` or if either are strictly greater than
|
||||||
|
/// `self.len()`.
|
||||||
|
pub fn slice(mut self, lo: usize, hi: usize) -> ArcSlice<T> {
|
||||||
|
self.data = &self[lo..hi];
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Construct a new `ArcSlice` that only points to elements at
|
||||||
|
/// indices up to `hi` (exclusive).
|
||||||
|
///
|
||||||
|
/// This consumes `self` to avoid unnecessary reference-count
|
||||||
|
/// modifications. Use `.clone()` if it is necessary to refer to
|
||||||
|
/// `self` after calling this.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `hi > self.len()`.
|
||||||
|
pub fn slice_to(self, hi: usize) -> ArcSlice<T> {
|
||||||
|
self.slice(0, hi)
|
||||||
|
}
|
||||||
|
/// Construct a new `ArcSlice` that only points to elements at
|
||||||
|
/// indices starting at `lo` (inclusive).
|
||||||
|
///
|
||||||
|
/// This consumes `self` to avoid unnecessary reference-count
|
||||||
|
/// modifications. Use `.clone()` if it is necessary to refer to
|
||||||
|
/// `self` after calling this.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `lo > self.len()`.
|
||||||
|
pub fn slice_from(self, lo: usize) -> ArcSlice<T> {
|
||||||
|
let hi = self.len();
|
||||||
|
self.slice(lo, hi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for ArcSlice<T> {
|
||||||
|
fn clone(&self) -> ArcSlice<T> {
|
||||||
|
ArcSlice {
|
||||||
|
data: self.data,
|
||||||
|
counts: self.counts.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ops::Deref for ArcSlice<T> {
|
||||||
|
type Target = [T];
|
||||||
|
fn deref<'a>(&'a self) -> &'a [T] {
|
||||||
|
unsafe { &*self.data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsRef<[T]> for ArcSlice<T> {
|
||||||
|
fn as_ref(&self) -> &[T] { &**self }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> PartialEq for ArcSlice<T> {
|
||||||
|
fn eq(&self, other: &ArcSlice<T>) -> bool { **self == **other }
|
||||||
|
fn ne(&self, other: &ArcSlice<T>) -> bool { **self != **other }
|
||||||
|
}
|
||||||
|
impl<T: Eq> Eq for ArcSlice<T> {}
|
||||||
|
|
||||||
|
impl<T: PartialOrd> PartialOrd for ArcSlice<T> {
|
||||||
|
fn partial_cmp(&self, other: &ArcSlice<T>) -> Option<cmp::Ordering> {
|
||||||
|
(**self).partial_cmp(&**other)
|
||||||
|
}
|
||||||
|
fn lt(&self, other: &ArcSlice<T>) -> bool { **self < **other }
|
||||||
|
fn le(&self, other: &ArcSlice<T>) -> bool { **self <= **other }
|
||||||
|
fn gt(&self, other: &ArcSlice<T>) -> bool { **self > **other }
|
||||||
|
fn ge(&self, other: &ArcSlice<T>) -> bool { **self >= **other }
|
||||||
|
}
|
||||||
|
impl<T: Ord> Ord for ArcSlice<T> {
|
||||||
|
fn cmp(&self, other: &ArcSlice<T>) -> cmp::Ordering { (**self).cmp(&**other) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash> Hash for ArcSlice<T> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
Hash::hash(&**self, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for ArcSlice<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(&**self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> WeakSlice<T> {
|
||||||
|
/// Attempt to upgrade `self` to a strongly-counted `ArcSlice`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if this is not possible (the data has already
|
||||||
|
/// been freed).
|
||||||
|
pub fn upgrade(&self) -> Option<ArcSlice<T>> {
|
||||||
|
self.counts.upgrade().map(|counts| {
|
||||||
|
ArcSlice {
|
||||||
|
data: self.data,
|
||||||
|
counts: counts
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use super::{ArcSlice, WeakSlice};
|
||||||
|
#[test]
|
||||||
|
fn clone() {
|
||||||
|
let x = ArcSlice::new(Box::new([Cell::new(false)]));
|
||||||
|
let y = x.clone();
|
||||||
|
|
||||||
|
assert_eq!(x[0].get(), false);
|
||||||
|
assert_eq!(y[0].get(), false);
|
||||||
|
|
||||||
|
x[0].set(true);
|
||||||
|
assert_eq!(x[0].get(), true);
|
||||||
|
assert_eq!(y[0].get(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_upgrade_downgrade() {
|
||||||
|
let x = ArcSlice::new(Box::new([1]));
|
||||||
|
let y: WeakSlice<_> = x.downgrade();
|
||||||
|
|
||||||
|
assert_eq!(y.upgrade(), Some(x.clone()));
|
||||||
|
|
||||||
|
drop(x);
|
||||||
|
|
||||||
|
assert!(y.upgrade().is_none())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_total_cmp() {
|
||||||
|
let x = ArcSlice::new(Box::new([1, 2, 3]));
|
||||||
|
let y = ArcSlice::new(Box::new([1, 2, 3]));
|
||||||
|
let z = ArcSlice::new(Box::new([1, 2, 4]));
|
||||||
|
|
||||||
|
assert_eq!(x, x);
|
||||||
|
assert_eq!(x, y);
|
||||||
|
assert!(x != z);
|
||||||
|
assert!(y != z);
|
||||||
|
|
||||||
|
assert!(x < z);
|
||||||
|
assert!(x <= z);
|
||||||
|
assert!(!(x > z));
|
||||||
|
assert!(!(x >= z));
|
||||||
|
|
||||||
|
assert!(!(z < x));
|
||||||
|
assert!(!(z <= x));
|
||||||
|
assert!(z > x);
|
||||||
|
assert!(z >= x);
|
||||||
|
|
||||||
|
assert_eq!(x.partial_cmp(&x), Some(Ordering::Equal));
|
||||||
|
assert_eq!(x.partial_cmp(&y), Some(Ordering::Equal));
|
||||||
|
assert_eq!(x.partial_cmp(&z), Some(Ordering::Less));
|
||||||
|
assert_eq!(z.partial_cmp(&y), Some(Ordering::Greater));
|
||||||
|
|
||||||
|
assert_eq!(x.cmp(&x), Ordering::Equal);
|
||||||
|
assert_eq!(x.cmp(&y), Ordering::Equal);
|
||||||
|
assert_eq!(x.cmp(&z), Ordering::Less);
|
||||||
|
assert_eq!(z.cmp(&y), Ordering::Greater);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_partial_cmp() {
|
||||||
|
use std::f64;
|
||||||
|
let x = ArcSlice::new(Box::new([1.0, f64::NAN]));
|
||||||
|
let y = ArcSlice::new(Box::new([1.0, f64::NAN]));
|
||||||
|
let z = ArcSlice::new(Box::new([2.0, f64::NAN]));
|
||||||
|
let w = ArcSlice::new(Box::new([f64::NAN, 1.0]));
|
||||||
|
assert!(!(x == y));
|
||||||
|
assert!(x != y);
|
||||||
|
|
||||||
|
assert!(!(x < y));
|
||||||
|
assert!(!(x <= y));
|
||||||
|
assert!(!(x > y));
|
||||||
|
assert!(!(x >= y));
|
||||||
|
|
||||||
|
assert!(x < z);
|
||||||
|
assert!(x <= z);
|
||||||
|
assert!(!(x > z));
|
||||||
|
assert!(!(x >= z));
|
||||||
|
|
||||||
|
assert!(!(z < w));
|
||||||
|
assert!(!(z <= w));
|
||||||
|
assert!(!(z > w));
|
||||||
|
assert!(!(z >= w));
|
||||||
|
|
||||||
|
assert_eq!(x.partial_cmp(&x), None);
|
||||||
|
assert_eq!(x.partial_cmp(&y), None);
|
||||||
|
assert_eq!(x.partial_cmp(&z), Some(Ordering::Less));
|
||||||
|
assert_eq!(z.partial_cmp(&x), Some(Ordering::Greater));
|
||||||
|
|
||||||
|
assert_eq!(x.partial_cmp(&w), None);
|
||||||
|
assert_eq!(y.partial_cmp(&w), None);
|
||||||
|
assert_eq!(z.partial_cmp(&w), None);
|
||||||
|
assert_eq!(w.partial_cmp(&w), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_show() {
|
||||||
|
let x = ArcSlice::new(Box::new([1, 2]));
|
||||||
|
assert_eq!(format!("{:?}", x), "[1, 2]");
|
||||||
|
|
||||||
|
let y: ArcSlice<i32> = ArcSlice::new(Box::new([]));
|
||||||
|
assert_eq!(format!("{:?}", y), "[]");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice() {
|
||||||
|
let x = ArcSlice::new(Box::new([1, 2, 3]));
|
||||||
|
let real = [1, 2, 3];
|
||||||
|
for i in 0..3 + 1 {
|
||||||
|
for j in i..3 + 1 {
|
||||||
|
let slice: ArcSlice<_> = x.clone().slice(i, j);
|
||||||
|
assert_eq!(&*slice, &real[i..j]);
|
||||||
|
}
|
||||||
|
assert_eq!(&*x.clone().slice_to(i), &real[..i]);
|
||||||
|
assert_eq!(&*x.clone().slice_from(i), &real[i..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_send_sync() {
|
||||||
|
fn assert_send<T: Send>() {}
|
||||||
|
fn assert_sync<T: Send>() {}
|
||||||
|
|
||||||
|
assert_send::<ArcSlice<u8>>();
|
||||||
|
assert_sync::<ArcSlice<u8>>();
|
||||||
|
assert_send::<WeakSlice<u8>>();
|
||||||
|
assert_sync::<WeakSlice<u8>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_drop() {
|
||||||
|
let drop_flag = Arc::new(Mutex::new(0));
|
||||||
|
struct Foo(Arc<Mutex<i32>>);
|
||||||
|
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut n = self.0.lock().unwrap();
|
||||||
|
*n += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let whole = ArcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())]));
|
||||||
|
|
||||||
|
drop(whole);
|
||||||
|
assert_eq!(*drop_flag.lock().unwrap(), 2);
|
||||||
|
|
||||||
|
*drop_flag.lock().unwrap() = 0;
|
||||||
|
|
||||||
|
let whole = ArcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())]));
|
||||||
|
let part = whole.slice(1, 2);
|
||||||
|
drop(part);
|
||||||
|
assert_eq!(*drop_flag.lock().unwrap(), 2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ extern crate fnv;
|
||||||
extern crate precomputed_hash;
|
extern crate precomputed_hash;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
|
|
||||||
|
pub mod arcslice;
|
||||||
pub mod bloom;
|
pub mod bloom;
|
||||||
pub mod matching;
|
pub mod matching;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
use bloom::BloomFilter;
|
use bloom::BloomFilter;
|
||||||
use parser::{CaseSensitivity, Combinator, ComplexSelector, LocalName};
|
use parser::{CaseSensitivity, Combinator, ComplexSelector, Component, LocalName};
|
||||||
use parser::{SimpleSelector, Selector, SelectorInner};
|
use parser::{Selector, SelectorInner, SelectorIter};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use tree::Element;
|
use tree::Element;
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
|
||||||
where E: Element,
|
where E: Element,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
{
|
{
|
||||||
match matches_complex_selector_internal(selector,
|
match matches_complex_selector_internal(selector.iter(),
|
||||||
element,
|
element,
|
||||||
relations,
|
relations,
|
||||||
flags_setter) {
|
flags_setter) {
|
||||||
|
@ -216,7 +216,7 @@ pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_complex_selector_internal<E, F>(selector: &ComplexSelector<E::Impl>,
|
fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
relations: &mut StyleRelations,
|
relations: &mut StyleRelations,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
|
@ -224,14 +224,12 @@ fn matches_complex_selector_internal<E, F>(selector: &ComplexSelector<E::Impl>,
|
||||||
where E: Element,
|
where E: Element,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
{
|
{
|
||||||
let matches_all_simple_selectors = selector.compound_selector.iter().all(|simple| {
|
let matches_all_simple_selectors = selector_iter.all(|simple| {
|
||||||
matches_simple_selector(simple, element, relations, flags_setter)
|
matches_simple_selector(simple, element, relations, flags_setter)
|
||||||
});
|
});
|
||||||
|
|
||||||
let siblings = selector.next.as_ref().map_or(false, |&(_, combinator)| {
|
let combinator = selector_iter.next_sequence();
|
||||||
matches!(combinator, Combinator::NextSibling | Combinator::LaterSibling)
|
let siblings = combinator.map_or(false, |c| c.is_sibling());
|
||||||
});
|
|
||||||
|
|
||||||
if siblings {
|
if siblings {
|
||||||
flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
||||||
}
|
}
|
||||||
|
@ -240,9 +238,9 @@ fn matches_complex_selector_internal<E, F>(selector: &ComplexSelector<E::Impl>,
|
||||||
return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
|
return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
match selector.next {
|
match combinator {
|
||||||
None => SelectorMatchingResult::Matched,
|
None => SelectorMatchingResult::Matched,
|
||||||
Some((ref next_selector, combinator)) => {
|
Some(c) => {
|
||||||
let (mut next_element, candidate_not_found) = if siblings {
|
let (mut next_element, candidate_not_found) = if siblings {
|
||||||
(element.prev_sibling_element(),
|
(element.prev_sibling_element(),
|
||||||
SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
|
SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
|
||||||
|
@ -256,11 +254,11 @@ fn matches_complex_selector_internal<E, F>(selector: &ComplexSelector<E::Impl>,
|
||||||
None => return candidate_not_found,
|
None => return candidate_not_found,
|
||||||
Some(next_element) => next_element,
|
Some(next_element) => next_element,
|
||||||
};
|
};
|
||||||
let result = matches_complex_selector_internal(&**next_selector,
|
let result = matches_complex_selector_internal(selector_iter.clone(),
|
||||||
&element,
|
&element,
|
||||||
relations,
|
relations,
|
||||||
flags_setter);
|
flags_setter);
|
||||||
match (result, combinator) {
|
match (result, c) {
|
||||||
// Return the status immediately.
|
// Return the status immediately.
|
||||||
(SelectorMatchingResult::Matched, _) => return result,
|
(SelectorMatchingResult::Matched, _) => return result,
|
||||||
(SelectorMatchingResult::NotMatchedGlobally, _) => return result,
|
(SelectorMatchingResult::NotMatchedGlobally, _) => return result,
|
||||||
|
@ -299,7 +297,7 @@ fn matches_complex_selector_internal<E, F>(selector: &ComplexSelector<E::Impl>,
|
||||||
/// Determines whether the given element matches the given single selector.
|
/// Determines whether the given element matches the given single selector.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_simple_selector<E, F>(
|
fn matches_simple_selector<E, F>(
|
||||||
selector: &SimpleSelector<E::Impl>,
|
selector: &Component<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
relations: &mut StyleRelations,
|
relations: &mut StyleRelations,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
|
@ -319,109 +317,110 @@ fn matches_simple_selector<E, F>(
|
||||||
}
|
}
|
||||||
|
|
||||||
match *selector {
|
match *selector {
|
||||||
SimpleSelector::LocalName(LocalName { ref name, ref lower_name }) => {
|
Component::Combinator(_) => unreachable!(),
|
||||||
|
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
||||||
let name = if element.is_html_element_in_html_document() { lower_name } else { 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() == name.borrow()
|
||||||
}
|
}
|
||||||
SimpleSelector::Namespace(ref namespace) => {
|
Component::Namespace(ref namespace) => {
|
||||||
element.get_namespace() == namespace.url.borrow()
|
element.get_namespace() == namespace.url.borrow()
|
||||||
}
|
}
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||||
SimpleSelector::ID(ref id) => {
|
Component::ID(ref id) => {
|
||||||
relation_if!(element.get_id().map_or(false, |attr| attr == *id),
|
relation_if!(element.get_id().map_or(false, |attr| attr == *id),
|
||||||
AFFECTED_BY_ID_SELECTOR)
|
AFFECTED_BY_ID_SELECTOR)
|
||||||
}
|
}
|
||||||
SimpleSelector::Class(ref class) => {
|
Component::Class(ref class) => {
|
||||||
element.has_class(class)
|
element.has_class(class)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrExists(ref attr) => {
|
Component::AttrExists(ref attr) => {
|
||||||
element.match_attr_has(attr)
|
element.match_attr_has(attr)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrEqual(ref attr, ref value, case_sensitivity) => {
|
Component::AttrEqual(ref attr, ref value, case_sensitivity) => {
|
||||||
match case_sensitivity {
|
match case_sensitivity {
|
||||||
CaseSensitivity::CaseSensitive => element.match_attr_equals(attr, value),
|
CaseSensitivity::CaseSensitive => element.match_attr_equals(attr, value),
|
||||||
CaseSensitivity::CaseInsensitive => element.match_attr_equals_ignore_ascii_case(attr, value),
|
CaseSensitivity::CaseInsensitive => element.match_attr_equals_ignore_ascii_case(attr, value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrIncludes(ref attr, ref value) => {
|
Component::AttrIncludes(ref attr, ref value) => {
|
||||||
element.match_attr_includes(attr, value)
|
element.match_attr_includes(attr, value)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrDashMatch(ref attr, ref value) => {
|
Component::AttrDashMatch(ref attr, ref value) => {
|
||||||
element.match_attr_dash(attr, value)
|
element.match_attr_dash(attr, value)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrPrefixMatch(ref attr, ref value) => {
|
Component::AttrPrefixMatch(ref attr, ref value) => {
|
||||||
element.match_attr_prefix(attr, value)
|
element.match_attr_prefix(attr, value)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrSubstringMatch(ref attr, ref value) => {
|
Component::AttrSubstringMatch(ref attr, ref value) => {
|
||||||
element.match_attr_substring(attr, value)
|
element.match_attr_substring(attr, value)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrSuffixMatch(ref attr, ref value) => {
|
Component::AttrSuffixMatch(ref attr, ref value) => {
|
||||||
element.match_attr_suffix(attr, value)
|
element.match_attr_suffix(attr, value)
|
||||||
}
|
}
|
||||||
SimpleSelector::AttrIncludesNeverMatch(..) |
|
Component::AttrIncludesNeverMatch(..) |
|
||||||
SimpleSelector::AttrPrefixNeverMatch(..) |
|
Component::AttrPrefixNeverMatch(..) |
|
||||||
SimpleSelector::AttrSubstringNeverMatch(..) |
|
Component::AttrSubstringNeverMatch(..) |
|
||||||
SimpleSelector::AttrSuffixNeverMatch(..) => {
|
Component::AttrSuffixNeverMatch(..) => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
SimpleSelector::NonTSPseudoClass(ref pc) => {
|
Component::NonTSPseudoClass(ref pc) => {
|
||||||
relation_if!(element.match_non_ts_pseudo_class(pc, relations, flags_setter),
|
relation_if!(element.match_non_ts_pseudo_class(pc, relations, flags_setter),
|
||||||
AFFECTED_BY_STATE)
|
AFFECTED_BY_STATE)
|
||||||
}
|
}
|
||||||
SimpleSelector::FirstChild => {
|
Component::FirstChild => {
|
||||||
relation_if!(matches_first_child(element, flags_setter),
|
relation_if!(matches_first_child(element, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::LastChild => {
|
Component::LastChild => {
|
||||||
relation_if!(matches_last_child(element, flags_setter),
|
relation_if!(matches_last_child(element, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::OnlyChild => {
|
Component::OnlyChild => {
|
||||||
relation_if!(matches_first_child(element, flags_setter) &&
|
relation_if!(matches_first_child(element, flags_setter) &&
|
||||||
matches_last_child(element, flags_setter),
|
matches_last_child(element, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::Root => {
|
Component::Root => {
|
||||||
// We never share styles with an element with no parent, so no point
|
// We never share styles with an element with no parent, so no point
|
||||||
// in creating a new StyleRelation.
|
// in creating a new StyleRelation.
|
||||||
element.is_root()
|
element.is_root()
|
||||||
}
|
}
|
||||||
SimpleSelector::Empty => {
|
Component::Empty => {
|
||||||
flags_setter(element, HAS_EMPTY_SELECTOR);
|
flags_setter(element, HAS_EMPTY_SELECTOR);
|
||||||
relation_if!(element.is_empty(), AFFECTED_BY_EMPTY)
|
relation_if!(element.is_empty(), AFFECTED_BY_EMPTY)
|
||||||
}
|
}
|
||||||
SimpleSelector::NthChild(a, b) => {
|
Component::NthChild(a, b) => {
|
||||||
relation_if!(matches_generic_nth_child(element, a, b, false, false, flags_setter),
|
relation_if!(matches_generic_nth_child(element, a, b, false, false, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::NthLastChild(a, b) => {
|
Component::NthLastChild(a, b) => {
|
||||||
relation_if!(matches_generic_nth_child(element, a, b, false, true, flags_setter),
|
relation_if!(matches_generic_nth_child(element, a, b, false, true, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::NthOfType(a, b) => {
|
Component::NthOfType(a, b) => {
|
||||||
relation_if!(matches_generic_nth_child(element, a, b, true, false, flags_setter),
|
relation_if!(matches_generic_nth_child(element, a, b, true, false, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::NthLastOfType(a, b) => {
|
Component::NthLastOfType(a, b) => {
|
||||||
relation_if!(matches_generic_nth_child(element, a, b, true, true, flags_setter),
|
relation_if!(matches_generic_nth_child(element, a, b, true, true, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::FirstOfType => {
|
Component::FirstOfType => {
|
||||||
relation_if!(matches_generic_nth_child(element, 0, 1, true, false, flags_setter),
|
relation_if!(matches_generic_nth_child(element, 0, 1, true, false, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::LastOfType => {
|
Component::LastOfType => {
|
||||||
relation_if!(matches_generic_nth_child(element, 0, 1, true, true, flags_setter),
|
relation_if!(matches_generic_nth_child(element, 0, 1, true, true, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::OnlyOfType => {
|
Component::OnlyOfType => {
|
||||||
relation_if!(matches_generic_nth_child(element, 0, 1, true, false, flags_setter) &&
|
relation_if!(matches_generic_nth_child(element, 0, 1, true, false, flags_setter) &&
|
||||||
matches_generic_nth_child(element, 0, 1, true, true, flags_setter),
|
matches_generic_nth_child(element, 0, 1, true, true, flags_setter),
|
||||||
AFFECTED_BY_CHILD_INDEX)
|
AFFECTED_BY_CHILD_INDEX)
|
||||||
}
|
}
|
||||||
SimpleSelector::Negation(ref negated) => {
|
Component::Negation(ref negated) => {
|
||||||
!negated.iter().all(|s| {
|
!negated.iter().all(|s| {
|
||||||
match matches_complex_selector_internal(s,
|
match matches_complex_selector_internal(s.iter(),
|
||||||
element,
|
element,
|
||||||
relations,
|
relations,
|
||||||
flags_setter) {
|
flags_setter) {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use parser::{AttrSelector, Combinator, ComplexSelector, SelectorImpl, SimpleSelector};
|
use parser::{AttrSelector, Combinator, Component};
|
||||||
|
use parser::{SelectorImpl, SelectorIter};
|
||||||
|
|
||||||
/// A trait to visit selector properties.
|
/// A trait to visit selector properties.
|
||||||
///
|
///
|
||||||
|
@ -24,7 +25,7 @@ pub trait SelectorVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit a simple selector.
|
/// Visit a simple selector.
|
||||||
fn visit_simple_selector(&mut self, _: &SimpleSelector<Self::Impl>) -> bool {
|
fn visit_simple_selector(&mut self, _: &Component<Self::Impl>) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ pub trait SelectorVisitor {
|
||||||
/// Gets the combinator to the right of the selector, or `None` if the
|
/// Gets the combinator to the right of the selector, or `None` if the
|
||||||
/// selector is the leftmost one.
|
/// selector is the leftmost one.
|
||||||
fn visit_complex_selector(&mut self,
|
fn visit_complex_selector(&mut self,
|
||||||
_: &ComplexSelector<Self::Impl>,
|
_: SelectorIter<Self::Impl>,
|
||||||
_combinator_to_right: Option<Combinator>)
|
_combinator_to_right: Option<Combinator>)
|
||||||
-> bool {
|
-> bool {
|
||||||
true
|
true
|
||||||
|
|
|
@ -14,7 +14,6 @@ use selectors::visitor::SelectorVisitor;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Arc;
|
|
||||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
|
|
||||||
/// A representation of a CSS pseudo-element.
|
/// A representation of a CSS pseudo-element.
|
||||||
|
@ -218,7 +217,7 @@ macro_rules! pseudo_class_name {
|
||||||
///
|
///
|
||||||
/// TODO(emilio): We disallow combinators and pseudos here, so we
|
/// TODO(emilio): We disallow combinators and pseudos here, so we
|
||||||
/// should use SimpleSelector instead
|
/// should use SimpleSelector instead
|
||||||
MozAny(Vec<Arc<ComplexSelector<SelectorImpl>>>),
|
MozAny(Box<[ComplexSelector<SelectorImpl>]>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +266,7 @@ impl SelectorMethods for NonTSPseudoClass {
|
||||||
where V: SelectorVisitor<Impl = Self::Impl>,
|
where V: SelectorVisitor<Impl = Self::Impl>,
|
||||||
{
|
{
|
||||||
if let NonTSPseudoClass::MozAny(ref selectors) = *self {
|
if let NonTSPseudoClass::MozAny(ref selectors) = *self {
|
||||||
for selector in selectors {
|
for selector in selectors.iter() {
|
||||||
if !selector.visit(visitor) {
|
if !selector.visit(visitor) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -396,13 +395,13 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
||||||
}, )*
|
}, )*
|
||||||
"-moz-any" => {
|
"-moz-any" => {
|
||||||
let selectors = parser.parse_comma_separated(|input| {
|
let selectors = parser.parse_comma_separated(|input| {
|
||||||
ComplexSelector::parse(self, input).map(Arc::new)
|
ComplexSelector::parse(self, input)
|
||||||
})?;
|
})?;
|
||||||
// Selectors inside `:-moz-any` may not include combinators.
|
// Selectors inside `:-moz-any` may not include combinators.
|
||||||
if selectors.iter().any(|s| s.next.is_some()) {
|
if selectors.iter().flat_map(|x| x.iter_raw()).any(|s| s.is_combinator()) {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::MozAny(selectors)
|
NonTSPseudoClass::MozAny(selectors.into_boxed_slice())
|
||||||
}
|
}
|
||||||
_ => return Err(())
|
_ => return Err(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1198,11 +1198,11 @@ pub trait MatchMethods : TElement {
|
||||||
// > fn with_really_simple_selectors(&self, f: <H: Hash>|&H|);
|
// > fn with_really_simple_selectors(&self, f: <H: Hash>|&H|);
|
||||||
|
|
||||||
|
|
||||||
// In terms of `SimpleSelector`s, these two functions will insert and remove:
|
// In terms of `Component`s, these two functions will insert and remove:
|
||||||
// - `SimpleSelector::LocalName`
|
// - `Component::LocalName`
|
||||||
// - `SimpleSelector::Namepace`
|
// - `Component::Namepace`
|
||||||
// - `SimpleSelector::ID`
|
// - `Component::ID`
|
||||||
// - `SimpleSelector::Class`
|
// - `Component::Class`
|
||||||
|
|
||||||
/// Inserts and removes the matching `Descendant` selectors from a bloom
|
/// Inserts and removes the matching `Descendant` selectors from a bloom
|
||||||
/// filter. This is used to speed up CSS selector matching to remove
|
/// filter. This is used to speed up CSS selector matching to remove
|
||||||
|
|
|
@ -17,10 +17,10 @@ use selector_parser::{AttrValue, NonTSPseudoClass, Snapshot, SelectorImpl};
|
||||||
use selectors::{Element, MatchAttr};
|
use selectors::{Element, MatchAttr};
|
||||||
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||||
use selectors::matching::matches_selector;
|
use selectors::matching::matches_selector;
|
||||||
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorInner, SelectorMethods, SimpleSelector};
|
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, Component};
|
||||||
|
use selectors::parser::{SelectorInner, SelectorIter, SelectorMethods};
|
||||||
use selectors::visitor::SelectorVisitor;
|
use selectors::visitor::SelectorVisitor;
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// When the ElementState of an element (like IN_HOVER_STATE) changes,
|
/// When the ElementState of an element (like IN_HOVER_STATE) changes,
|
||||||
|
@ -388,24 +388,24 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selector_to_state(sel: &SimpleSelector<SelectorImpl>) -> ElementState {
|
fn selector_to_state(sel: &Component<SelectorImpl>) -> ElementState {
|
||||||
match *sel {
|
match *sel {
|
||||||
SimpleSelector::NonTSPseudoClass(ref pc) => pc.state_flag(),
|
Component::NonTSPseudoClass(ref pc) => pc.state_flag(),
|
||||||
_ => ElementState::empty(),
|
_ => ElementState::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_attr_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
|
fn is_attr_selector(sel: &Component<SelectorImpl>) -> bool {
|
||||||
match *sel {
|
match *sel {
|
||||||
SimpleSelector::ID(_) |
|
Component::ID(_) |
|
||||||
SimpleSelector::Class(_) |
|
Component::Class(_) |
|
||||||
SimpleSelector::AttrExists(_) |
|
Component::AttrExists(_) |
|
||||||
SimpleSelector::AttrEqual(_, _, _) |
|
Component::AttrEqual(_, _, _) |
|
||||||
SimpleSelector::AttrIncludes(_, _) |
|
Component::AttrIncludes(_, _) |
|
||||||
SimpleSelector::AttrDashMatch(_, _) |
|
Component::AttrDashMatch(_, _) |
|
||||||
SimpleSelector::AttrPrefixMatch(_, _) |
|
Component::AttrPrefixMatch(_, _) |
|
||||||
SimpleSelector::AttrSubstringMatch(_, _) |
|
Component::AttrSubstringMatch(_, _) |
|
||||||
SimpleSelector::AttrSuffixMatch(_, _) => true,
|
Component::AttrSuffixMatch(_, _) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -416,22 +416,22 @@ fn is_attr_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
|
||||||
///
|
///
|
||||||
/// We use this for selectors that can have different matching behavior between
|
/// We use this for selectors that can have different matching behavior between
|
||||||
/// siblings that are otherwise identical as far as the cache is concerned.
|
/// siblings that are otherwise identical as far as the cache is concerned.
|
||||||
fn needs_cache_revalidation(sel: &SimpleSelector<SelectorImpl>) -> bool {
|
fn needs_cache_revalidation(sel: &Component<SelectorImpl>) -> bool {
|
||||||
match *sel {
|
match *sel {
|
||||||
SimpleSelector::Empty |
|
Component::Empty |
|
||||||
SimpleSelector::FirstChild |
|
Component::FirstChild |
|
||||||
SimpleSelector::LastChild |
|
Component::LastChild |
|
||||||
SimpleSelector::OnlyChild |
|
Component::OnlyChild |
|
||||||
SimpleSelector::NthChild(..) |
|
Component::NthChild(..) |
|
||||||
SimpleSelector::NthLastChild(..) |
|
Component::NthLastChild(..) |
|
||||||
SimpleSelector::NthOfType(..) |
|
Component::NthOfType(..) |
|
||||||
SimpleSelector::NthLastOfType(..) |
|
Component::NthLastOfType(..) |
|
||||||
SimpleSelector::FirstOfType |
|
Component::FirstOfType |
|
||||||
SimpleSelector::LastOfType |
|
Component::LastOfType |
|
||||||
SimpleSelector::OnlyOfType => true,
|
Component::OnlyOfType => true,
|
||||||
// FIXME(emilio): This sets the "revalidation" flag for :any, which is
|
// FIXME(emilio): This sets the "revalidation" flag for :any, which is
|
||||||
// probably expensive given we use it a lot in UA sheets.
|
// probably expensive given we use it a lot in UA sheets.
|
||||||
SimpleSelector::NonTSPseudoClass(ref p) => p.state_flag().is_empty(),
|
Component::NonTSPseudoClass(ref p) => p.state_flag().is_empty(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,7 +509,7 @@ impl SelectorVisitor for SensitivitiesVisitor {
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
fn visit_complex_selector(&mut self,
|
fn visit_complex_selector(&mut self,
|
||||||
_: &ComplexSelector<SelectorImpl>,
|
_: SelectorIter<SelectorImpl>,
|
||||||
combinator: Option<Combinator>) -> bool {
|
combinator: Option<Combinator>) -> bool {
|
||||||
self.hint |= combinator_to_restyle_hint(combinator);
|
self.hint |= combinator_to_restyle_hint(combinator);
|
||||||
self.needs_revalidation |= self.hint.contains(RESTYLE_LATER_SIBLINGS);
|
self.needs_revalidation |= self.hint.contains(RESTYLE_LATER_SIBLINGS);
|
||||||
|
@ -517,7 +517,7 @@ impl SelectorVisitor for SensitivitiesVisitor {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_simple_selector(&mut self, s: &SimpleSelector<SelectorImpl>) -> bool {
|
fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
|
||||||
self.sensitivities.states.insert(selector_to_state(s));
|
self.sensitivities.states.insert(selector_to_state(s));
|
||||||
|
|
||||||
if !self.sensitivities.attrs {
|
if !self.sensitivities.attrs {
|
||||||
|
@ -567,50 +567,47 @@ impl DependencySet {
|
||||||
/// cache revalidation, that is, whether two siblings of the same "shape"
|
/// cache revalidation, that is, whether two siblings of the same "shape"
|
||||||
/// may have different style due to this selector.
|
/// may have different style due to this selector.
|
||||||
pub fn note_selector(&mut self,
|
pub fn note_selector(&mut self,
|
||||||
selector: &Arc<ComplexSelector<SelectorImpl>>)
|
base: &ComplexSelector<SelectorImpl>)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
|
let mut next = Some(base.clone());
|
||||||
let mut combinator = None;
|
let mut combinator = None;
|
||||||
let mut current = selector;
|
|
||||||
|
|
||||||
let mut needs_revalidation = false;
|
let mut needs_revalidation = false;
|
||||||
|
|
||||||
loop {
|
while let Some(current) = next.take() {
|
||||||
let mut sensitivities_visitor = SensitivitiesVisitor {
|
// Set up our visitor.
|
||||||
|
let mut visitor = SensitivitiesVisitor {
|
||||||
sensitivities: Sensitivities::new(),
|
sensitivities: Sensitivities::new(),
|
||||||
hint: RestyleHint::empty(),
|
hint: combinator_to_restyle_hint(combinator),
|
||||||
needs_revalidation: false,
|
needs_revalidation: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
for ss in ¤t.compound_selector {
|
{
|
||||||
ss.visit(&mut sensitivities_visitor);
|
// Visit all the simple selectors.
|
||||||
|
let mut iter = current.iter();
|
||||||
|
let mut index = 0usize;
|
||||||
|
for ss in &mut iter {
|
||||||
|
ss.visit(&mut visitor);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the next sequence of simple selectors.
|
||||||
|
if let Some(next_combinator) = iter.next_sequence() {
|
||||||
|
next = Some(current.slice_from(index + 1));
|
||||||
|
combinator = Some(next_combinator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
needs_revalidation |= sensitivities_visitor.needs_revalidation;
|
// Note what we found.
|
||||||
|
needs_revalidation |= visitor.needs_revalidation;
|
||||||
let SensitivitiesVisitor {
|
if !visitor.sensitivities.is_empty() {
|
||||||
sensitivities,
|
|
||||||
mut hint,
|
|
||||||
..
|
|
||||||
} = sensitivities_visitor;
|
|
||||||
|
|
||||||
hint |= combinator_to_restyle_hint(combinator);
|
|
||||||
|
|
||||||
if !sensitivities.is_empty() {
|
|
||||||
self.add_dependency(Dependency {
|
self.add_dependency(Dependency {
|
||||||
sensitivities: sensitivities,
|
sensitivities: visitor.sensitivities,
|
||||||
hint: hint,
|
hint: visitor.hint,
|
||||||
selector: SelectorInner::new(current.clone()),
|
selector: SelectorInner::new(current),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
match current.next {
|
|
||||||
Some((ref next, next_combinator)) => {
|
|
||||||
current = next;
|
|
||||||
combinator = Some(next_combinator);
|
|
||||||
}
|
|
||||||
None => break,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
needs_revalidation
|
needs_revalidation
|
||||||
|
@ -729,7 +726,7 @@ fn smoke_restyle_hints() {
|
||||||
let mut dependencies = DependencySet::new();
|
let mut dependencies = DependencySet::new();
|
||||||
|
|
||||||
let mut p = Parser::new(":not(:active) ~ label");
|
let mut p = Parser::new(":not(:active) ~ label");
|
||||||
let selector = Arc::new(ComplexSelector::parse(&parser, &mut p).unwrap());
|
let selector = ComplexSelector::parse(&parser, &mut p).unwrap();
|
||||||
dependencies.note_selector(&selector);
|
dependencies.note_selector(&selector);
|
||||||
assert_eq!(dependencies.len(), 1);
|
assert_eq!(dependencies.len(), 1);
|
||||||
assert_eq!(dependencies.state_deps.len(), 1);
|
assert_eq!(dependencies.state_deps.len(), 1);
|
||||||
|
|
|
@ -27,7 +27,7 @@ use selectors::bloom::BloomFilter;
|
||||||
use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
|
use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
|
||||||
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
||||||
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
|
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
|
||||||
use selectors::parser::{Selector, SelectorInner, SimpleSelector, LocalName as LocalNameSelector};
|
use selectors::parser::{Component, Selector, SelectorInner, LocalName as LocalNameSelector};
|
||||||
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
use smallvec::VecLike;
|
use smallvec::VecLike;
|
||||||
|
@ -1070,8 +1070,7 @@ impl SelectorMap {
|
||||||
// correct, and also to not trigger rule tree assertions.
|
// correct, and also to not trigger rule tree assertions.
|
||||||
let mut important = vec![];
|
let mut important = vec![];
|
||||||
for rule in self.other_rules.iter() {
|
for rule in self.other_rules.iter() {
|
||||||
if rule.selector.complex.compound_selector.is_empty() &&
|
if rule.selector.complex.iter_raw().next().is_none() {
|
||||||
rule.selector.complex.next.is_none() {
|
|
||||||
let style_rule = rule.style_rule.read_with(guard);
|
let style_rule = rule.style_rule.read_with(guard);
|
||||||
let block = style_rule.block.read_with(guard);
|
let block = style_rule.block.read_with(guard);
|
||||||
if block.any_normal() {
|
if block.any_normal() {
|
||||||
|
@ -1180,10 +1179,10 @@ impl SelectorMap {
|
||||||
|
|
||||||
/// Retrieve the first ID name in Rule, or None otherwise.
|
/// Retrieve the first ID name in Rule, or None otherwise.
|
||||||
pub fn get_id_name(rule: &Rule) -> Option<Atom> {
|
pub fn get_id_name(rule: &Rule) -> Option<Atom> {
|
||||||
for ss in &rule.selector.complex.compound_selector {
|
for ss in rule.selector.complex.iter() {
|
||||||
// TODO(pradeep): Implement case-sensitivity based on the
|
// TODO(pradeep): Implement case-sensitivity based on the
|
||||||
// document type and quirks mode.
|
// document type and quirks mode.
|
||||||
if let SimpleSelector::ID(ref id) = *ss {
|
if let Component::ID(ref id) = *ss {
|
||||||
return Some(id.clone());
|
return Some(id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1193,10 +1192,10 @@ impl SelectorMap {
|
||||||
|
|
||||||
/// Retrieve the FIRST class name in Rule, or None otherwise.
|
/// Retrieve the FIRST class name in Rule, or None otherwise.
|
||||||
pub fn get_class_name(rule: &Rule) -> Option<Atom> {
|
pub fn get_class_name(rule: &Rule) -> Option<Atom> {
|
||||||
for ss in &rule.selector.complex.compound_selector {
|
for ss in rule.selector.complex.iter() {
|
||||||
// TODO(pradeep): Implement case-sensitivity based on the
|
// TODO(pradeep): Implement case-sensitivity based on the
|
||||||
// document type and quirks mode.
|
// document type and quirks mode.
|
||||||
if let SimpleSelector::Class(ref class) = *ss {
|
if let Component::Class(ref class) = *ss {
|
||||||
return Some(class.clone());
|
return Some(class.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1206,8 +1205,8 @@ 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.
|
||||||
pub fn get_local_name(rule: &Rule) -> Option<LocalNameSelector<SelectorImpl>> {
|
pub fn get_local_name(rule: &Rule) -> Option<LocalNameSelector<SelectorImpl>> {
|
||||||
for ss in &rule.selector.complex.compound_selector {
|
for ss in rule.selector.complex.iter() {
|
||||||
if let SimpleSelector::LocalName(ref n) = *ss {
|
if let Component::LocalName(ref n) = *ss {
|
||||||
return Some(LocalNameSelector {
|
return Some(LocalNameSelector {
|
||||||
name: n.name.clone(),
|
name: n.name.clone(),
|
||||||
lower_name: n.lower_name.clone(),
|
lower_name: n.lower_name.clone(),
|
||||||
|
|
|
@ -84,27 +84,24 @@ fn test_parse_stylesheet() {
|
||||||
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
|
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
|
||||||
selectors: SelectorList(vec![
|
selectors: SelectorList(vec![
|
||||||
Selector {
|
Selector {
|
||||||
inner: SelectorInner::new(Arc::new(ComplexSelector {
|
inner: SelectorInner::from_vec(vec![
|
||||||
compound_selector: vec![
|
Component::Namespace(Namespace {
|
||||||
SimpleSelector::Namespace(Namespace {
|
prefix: None,
|
||||||
|
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
||||||
|
}),
|
||||||
|
Component::LocalName(LocalName {
|
||||||
|
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,
|
prefix: None,
|
||||||
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
url: ns!()
|
||||||
}),
|
}),
|
||||||
SimpleSelector::LocalName(LocalName {
|
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
|
||||||
name: local_name!("input"),
|
]),
|
||||||
lower_name: local_name!("input"),
|
|
||||||
}),
|
|
||||||
SimpleSelector::AttrEqual(AttrSelector {
|
|
||||||
name: local_name!("type"),
|
|
||||||
lower_name: local_name!("type"),
|
|
||||||
namespace: NamespaceConstraint::Specific(Namespace {
|
|
||||||
prefix: None,
|
|
||||||
url: ns!()
|
|
||||||
}),
|
|
||||||
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
|
|
||||||
],
|
|
||||||
next: None,
|
|
||||||
})),
|
|
||||||
pseudo_element: None,
|
pseudo_element: None,
|
||||||
specificity: (0 << 20) + (1 << 10) + (1 << 0),
|
specificity: (0 << 20) + (1 << 10) + (1 << 0),
|
||||||
},
|
},
|
||||||
|
@ -120,36 +117,30 @@ fn test_parse_stylesheet() {
|
||||||
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
|
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
|
||||||
selectors: SelectorList(vec![
|
selectors: SelectorList(vec![
|
||||||
Selector {
|
Selector {
|
||||||
inner: SelectorInner::new(Arc::new(ComplexSelector {
|
inner: SelectorInner::from_vec(vec![
|
||||||
compound_selector: vec![
|
Component::Namespace(Namespace {
|
||||||
SimpleSelector::Namespace(Namespace {
|
prefix: None,
|
||||||
prefix: None,
|
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
||||||
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
}),
|
||||||
}),
|
Component::LocalName(LocalName {
|
||||||
SimpleSelector::LocalName(LocalName {
|
name: local_name!("html"),
|
||||||
name: local_name!("html"),
|
lower_name: local_name!("html"),
|
||||||
lower_name: local_name!("html"),
|
}),
|
||||||
}),
|
]),
|
||||||
],
|
|
||||||
next: None,
|
|
||||||
})),
|
|
||||||
pseudo_element: None,
|
pseudo_element: None,
|
||||||
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||||
},
|
},
|
||||||
Selector {
|
Selector {
|
||||||
inner: SelectorInner::new(Arc::new(ComplexSelector {
|
inner: SelectorInner::from_vec(vec![
|
||||||
compound_selector: vec![
|
Component::Namespace(Namespace {
|
||||||
SimpleSelector::Namespace(Namespace {
|
prefix: None,
|
||||||
prefix: None,
|
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
||||||
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
}),
|
||||||
}),
|
Component::LocalName(LocalName {
|
||||||
SimpleSelector::LocalName(LocalName {
|
name: local_name!("body"),
|
||||||
name: local_name!("body"),
|
lower_name: local_name!("body"),
|
||||||
lower_name: local_name!("body"),
|
}),
|
||||||
}),
|
]),
|
||||||
],
|
|
||||||
next: None,
|
|
||||||
})),
|
|
||||||
pseudo_element: None,
|
pseudo_element: None,
|
||||||
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||||
},
|
},
|
||||||
|
@ -162,25 +153,19 @@ fn test_parse_stylesheet() {
|
||||||
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
|
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
|
||||||
selectors: SelectorList(vec![
|
selectors: SelectorList(vec![
|
||||||
Selector {
|
Selector {
|
||||||
inner: SelectorInner::new(Arc::new(ComplexSelector {
|
inner: SelectorInner::from_vec(vec![
|
||||||
compound_selector: vec![
|
Component::Namespace(Namespace {
|
||||||
SimpleSelector::Namespace(Namespace {
|
prefix: None,
|
||||||
prefix: None,
|
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
||||||
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
}),
|
||||||
}),
|
Component::ID(Atom::from("d1")),
|
||||||
SimpleSelector::Class(Atom::from("ok")),
|
Component::Combinator(Combinator::Child),
|
||||||
],
|
Component::Namespace(Namespace {
|
||||||
next: Some((Arc::new(ComplexSelector {
|
prefix: None,
|
||||||
compound_selector: vec![
|
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
||||||
SimpleSelector::Namespace(Namespace {
|
}),
|
||||||
prefix: None,
|
Component::Class(Atom::from("ok")),
|
||||||
url: NsAtom::from("http://www.w3.org/1999/xhtml")
|
]),
|
||||||
}),
|
|
||||||
SimpleSelector::ID(Atom::from("d1")),
|
|
||||||
],
|
|
||||||
next: None,
|
|
||||||
}), Combinator::Child)),
|
|
||||||
})),
|
|
||||||
pseudo_element: None,
|
pseudo_element: None,
|
||||||
specificity: (1 << 20) + (1 << 10) + (0 << 0),
|
specificity: (1 << 20) + (1 << 10) + (0 << 0),
|
||||||
},
|
},
|
||||||
|
|
|
@ -77,7 +77,7 @@ fn test_get_id_name() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_class_name() {
|
fn test_get_class_name() {
|
||||||
let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
|
let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
|
||||||
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro")));
|
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("foo")));
|
||||||
assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None);
|
assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +103,8 @@ fn test_insert() {
|
||||||
selector_map.insert(rules_list[1][0].clone());
|
selector_map.insert(rules_list[1][0].clone());
|
||||||
assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order);
|
assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order);
|
||||||
selector_map.insert(rules_list[0][0].clone());
|
selector_map.insert(rules_list[0][0].clone());
|
||||||
assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].source_order);
|
assert_eq!(0, selector_map.class_hash.get(&Atom::from("foo")).unwrap()[0].source_order);
|
||||||
assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none());
|
assert!(selector_map.class_hash.get(&Atom::from("intro")).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue