mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
servo: Merge #18595 - Implement an nth-index cache (from bholley:nth_index_cache); r=emilio
https://bugzilla.mozilla.org/show_bug.cgi?id=1334730 Source-Repo: https://github.com/servo/servo Source-Revision: be9c8ec07a0ca745adf1b412d32b3b32adec122c --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 3a03da9ae7e549b53b72306c7ec5f87365461470
This commit is contained in:
parent
27eb845182
commit
5f78e33b00
@ -630,6 +630,10 @@ fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
|
|||||||
impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
|
fn opaque(&self) -> ::selectors::OpaqueElement {
|
||||||
|
::selectors::OpaqueElement::new(self.as_node().opaque().0 as *const ())
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<ServoLayoutElement<'le>> {
|
fn parent_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.element.upcast().parent_node_ref().and_then(as_element)
|
self.element.upcast().parent_node_ref().and_then(as_element)
|
||||||
@ -1168,6 +1172,11 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
|
|||||||
impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
|
fn opaque(&self) -> ::selectors::OpaqueElement {
|
||||||
|
::selectors::OpaqueElement::new(self.as_node().opaque().0 as *const ())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<Self> {
|
fn parent_element(&self) -> Option<Self> {
|
||||||
warn!("ServoThreadSafeLayoutElement::parent_element called");
|
warn!("ServoThreadSafeLayoutElement::parent_element called");
|
||||||
None
|
None
|
||||||
|
@ -2500,6 +2500,10 @@ impl VirtualMethods for Element {
|
|||||||
impl<'a> ::selectors::Element for Root<Element> {
|
impl<'a> ::selectors::Element for Root<Element> {
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
|
fn opaque(&self) -> ::selectors::OpaqueElement {
|
||||||
|
::selectors::OpaqueElement::new(self.reflector().get_jsobject().get())
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<Root<Element>> {
|
fn parent_element(&self) -> Option<Root<Element>> {
|
||||||
self.upcast::<Node>().GetParentElement()
|
self.upcast::<Node>().GetParentElement()
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use attr::CaseSensitivity;
|
use attr::CaseSensitivity;
|
||||||
use bloom::BloomFilter;
|
use bloom::BloomFilter;
|
||||||
|
use nth_index_cache::NthIndexCache;
|
||||||
|
|
||||||
/// What kind of selector matching mode we should use.
|
/// What kind of selector matching mode we should use.
|
||||||
///
|
///
|
||||||
@ -69,12 +70,6 @@ impl QuirksMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A cache to speed up matching of nth-index-like selectors.
|
|
||||||
///
|
|
||||||
/// NB: This is just a dummy type right now, it will be fleshed out in later patches.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct NthIndexCache(usize);
|
|
||||||
|
|
||||||
/// Data associated with the matching process for a element. This context is
|
/// Data associated with the matching process for a element. This context is
|
||||||
/// used across many selectors for an element, so it's not appropriate for
|
/// used across many selectors for an element, so it's not appropriate for
|
||||||
/// transient data that applies to only a single selector.
|
/// transient data that applies to only a single selector.
|
||||||
@ -84,7 +79,7 @@ pub struct MatchingContext<'a> {
|
|||||||
/// Input with the bloom filter used to fast-reject selectors.
|
/// Input with the bloom filter used to fast-reject selectors.
|
||||||
pub bloom_filter: Option<&'a BloomFilter>,
|
pub bloom_filter: Option<&'a BloomFilter>,
|
||||||
/// An optional cache to speed up nth-index-like selectors.
|
/// An optional cache to speed up nth-index-like selectors.
|
||||||
nth_index_cache: Option<&'a mut NthIndexCache>,
|
pub nth_index_cache: Option<&'a mut NthIndexCache>,
|
||||||
/// Input that controls how matching for links is handled.
|
/// Input that controls how matching for links is handled.
|
||||||
pub visited_handling: VisitedHandlingMode,
|
pub visited_handling: VisitedHandlingMode,
|
||||||
/// Output that records whether we encountered a "relevant link" while
|
/// Output that records whether we encountered a "relevant link" while
|
||||||
|
@ -24,6 +24,7 @@ pub mod bloom;
|
|||||||
mod builder;
|
mod builder;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod matching;
|
pub mod matching;
|
||||||
|
mod nth_index_cache;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
#[cfg(test)] mod size_of_tests;
|
#[cfg(test)] mod size_of_tests;
|
||||||
#[cfg(any(test, feature = "gecko_like_types"))] pub mod gecko_like_types;
|
#[cfg(any(test, feature = "gecko_like_types"))] pub mod gecko_like_types;
|
||||||
@ -31,5 +32,6 @@ pub mod sink;
|
|||||||
mod tree;
|
mod tree;
|
||||||
pub mod visitor;
|
pub mod visitor;
|
||||||
|
|
||||||
|
pub use nth_index_cache::NthIndexCache;
|
||||||
pub use parser::{SelectorImpl, Parser, SelectorList};
|
pub use parser::{SelectorImpl, Parser, SelectorList};
|
||||||
pub use tree::Element;
|
pub use tree::{Element, OpaqueElement};
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
||||||
use bloom::{BLOOM_HASH_MASK, BloomFilter};
|
use bloom::{BLOOM_HASH_MASK, BloomFilter};
|
||||||
|
use nth_index_cache::NthIndexCacheInner;
|
||||||
use parser::{AncestorHashes, Combinator, Component, LocalName};
|
use parser::{AncestorHashes, Combinator, Component, LocalName};
|
||||||
use parser::{Selector, SelectorImpl, SelectorIter, SelectorList};
|
use parser::{Selector, SelectorImpl, SelectorIter, SelectorList};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
@ -787,7 +788,20 @@ fn matches_generic_nth_child<E, F>(element: &E,
|
|||||||
HAS_SLOW_SELECTOR_LATER_SIBLINGS
|
HAS_SLOW_SELECTOR_LATER_SIBLINGS
|
||||||
});
|
});
|
||||||
|
|
||||||
let index = nth_child_index(element, is_of_type, is_from_end);
|
// Grab a reference to the appropriate cache.
|
||||||
|
let mut cache = context.shared.nth_index_cache.as_mut().map(|c| {
|
||||||
|
c.get(is_of_type, is_from_end)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lookup or compute the index.
|
||||||
|
let index = if let Some(i) = cache.as_mut().and_then(|c| c.lookup(element.opaque())) {
|
||||||
|
i
|
||||||
|
} else {
|
||||||
|
let i = nth_child_index(element, is_of_type, is_from_end, cache.as_mut().map(|s| &mut **s));
|
||||||
|
cache.as_mut().map(|c| c.insert(element.opaque(), i));
|
||||||
|
i
|
||||||
|
};
|
||||||
|
debug_assert_eq!(index, nth_child_index(element, is_of_type, is_from_end, None), "invalid cache");
|
||||||
|
|
||||||
// Is there a non-negative integer n such that An+B=index?
|
// Is there a non-negative integer n such that An+B=index?
|
||||||
match index.checked_sub(b) {
|
match index.checked_sub(b) {
|
||||||
@ -799,41 +813,60 @@ fn matches_generic_nth_child<E, F>(element: &E,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn same_type<E: Element>(a: &E, b: &E) -> bool {
|
||||||
|
a.get_local_name() == b.get_local_name() &&
|
||||||
|
a.get_namespace() == b.get_namespace()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn nth_child_index<E>(
|
fn nth_child_index<E>(
|
||||||
element: &E,
|
element: &E,
|
||||||
is_of_type: bool,
|
is_of_type: bool,
|
||||||
is_from_end: bool,
|
is_from_end: bool,
|
||||||
|
mut cache: Option<&mut NthIndexCacheInner>,
|
||||||
) -> i32
|
) -> i32
|
||||||
where
|
where
|
||||||
E: Element,
|
E: Element,
|
||||||
{
|
{
|
||||||
let mut index: i32 = 1;
|
// The traversal mostly processes siblings left to right. So when we walk
|
||||||
let mut next_sibling = if is_from_end {
|
// siblings to the right when computing NthLast/NthLastOfType we're unlikely
|
||||||
element.next_sibling_element()
|
// to get cache hits along the way. As such, we take the hit of walking the
|
||||||
} else {
|
// siblings to the left checking the cache in the is_from_end case (this
|
||||||
element.prev_sibling_element()
|
// matches what Gecko does). The indices-from-the-left is handled during the
|
||||||
};
|
// regular look further below.
|
||||||
|
if let Some(ref mut c) = cache {
|
||||||
loop {
|
if is_from_end && !c.is_empty() {
|
||||||
let sibling = match next_sibling {
|
let mut index: i32 = 1;
|
||||||
None => break,
|
let mut curr = element.clone();
|
||||||
Some(next_sibling) => next_sibling
|
while let Some(e) = curr.prev_sibling_element() {
|
||||||
};
|
curr = e;
|
||||||
|
if !is_of_type || same_type(element, &curr) {
|
||||||
if is_of_type {
|
if let Some(i) = c.lookup(curr.opaque()) {
|
||||||
if element.get_local_name() == sibling.get_local_name() &&
|
return i - index;
|
||||||
element.get_namespace() == sibling.get_namespace() {
|
}
|
||||||
index += 1;
|
index += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
index += 1;
|
|
||||||
}
|
}
|
||||||
next_sibling = if is_from_end {
|
}
|
||||||
sibling.next_sibling_element()
|
|
||||||
} else {
|
let mut index: i32 = 1;
|
||||||
sibling.prev_sibling_element()
|
let mut curr = element.clone();
|
||||||
};
|
let next = |e: E| if is_from_end { e.next_sibling_element() } else { e.prev_sibling_element() };
|
||||||
|
while let Some(e) = next(curr) {
|
||||||
|
curr = e;
|
||||||
|
if !is_of_type || same_type(element, &curr) {
|
||||||
|
// If we're computing indices from the left, check each element in the
|
||||||
|
// cache. We handle the indices-from-the-right case at the top of this
|
||||||
|
// function.
|
||||||
|
if !is_from_end {
|
||||||
|
if let Some(i) = cache.as_mut().and_then(|c| c.lookup(curr.opaque())) {
|
||||||
|
return i + index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index
|
index
|
||||||
|
56
servo/components/selectors/nth_index_cache.rs
Normal file
56
servo/components/selectors/nth_index_cache.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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 fnv::FnvHashMap;
|
||||||
|
use tree::OpaqueElement;
|
||||||
|
|
||||||
|
/// A cache to speed up matching of nth-index-like selectors.
|
||||||
|
///
|
||||||
|
/// See [1] for some discussion around the design tradeoffs.
|
||||||
|
///
|
||||||
|
/// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1401855#c3
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NthIndexCache {
|
||||||
|
nth: NthIndexCacheInner,
|
||||||
|
nth_last: NthIndexCacheInner,
|
||||||
|
nth_of_type: NthIndexCacheInner,
|
||||||
|
nth_last_of_type: NthIndexCacheInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NthIndexCache {
|
||||||
|
/// Gets the appropriate cache for the given parameters.
|
||||||
|
pub fn get(
|
||||||
|
&mut self,
|
||||||
|
is_of_type: bool,
|
||||||
|
is_from_end: bool
|
||||||
|
) -> &mut NthIndexCacheInner {
|
||||||
|
match (is_of_type, is_from_end) {
|
||||||
|
(false, false) => &mut self.nth,
|
||||||
|
(false, true) => &mut self.nth_last,
|
||||||
|
(true, false) => &mut self.nth_of_type,
|
||||||
|
(true, true) => &mut self.nth_last_of_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The concrete per-pseudo-class cache.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NthIndexCacheInner(FnvHashMap<OpaqueElement, i32>);
|
||||||
|
|
||||||
|
impl NthIndexCacheInner {
|
||||||
|
/// Does a lookup for a given element in the cache.
|
||||||
|
pub fn lookup(&mut self, el: OpaqueElement) -> Option<i32> {
|
||||||
|
self.0.get(&el).map(|x| *x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts an entry into the cache.
|
||||||
|
pub fn insert(&mut self, element: OpaqueElement, index: i32) {
|
||||||
|
self.0.insert(element, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the cache is empty.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
}
|
@ -8,11 +8,27 @@
|
|||||||
use attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
|
use attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
|
||||||
use matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, RelevantLinkStatus};
|
use matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, RelevantLinkStatus};
|
||||||
use parser::SelectorImpl;
|
use parser::SelectorImpl;
|
||||||
|
use servo_arc::NonZeroPtrMut;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait Element: Sized + Debug {
|
/// Opaque representation of an Element, for identity comparisons. We use
|
||||||
|
/// NonZeroPtrMut to get the NonZero optimization.
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub struct OpaqueElement(pub NonZeroPtrMut<()>);
|
||||||
|
|
||||||
|
impl OpaqueElement {
|
||||||
|
/// Creates a new OpaqueElement from an arbitrarily-typed pointer.
|
||||||
|
pub fn new<T>(ptr: *const T) -> Self {
|
||||||
|
OpaqueElement(NonZeroPtrMut::new(ptr as *const () as *mut ()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Element: Sized + Clone + Debug {
|
||||||
type Impl: SelectorImpl;
|
type Impl: SelectorImpl;
|
||||||
|
|
||||||
|
/// Converts self into an opaque representation.
|
||||||
|
fn opaque(&self) -> OpaqueElement;
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<Self>;
|
fn parent_element(&self) -> Option<Self>;
|
||||||
|
|
||||||
/// The parent of a given pseudo-element, after matching a pseudo-element
|
/// The parent of a given pseudo-element, after matching a pseudo-element
|
||||||
|
@ -23,7 +23,7 @@ use properties::ComputedValues;
|
|||||||
use rule_cache::RuleCache;
|
use rule_cache::RuleCache;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
|
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
|
||||||
use selectors::context::NthIndexCache;
|
use selectors::NthIndexCache;
|
||||||
use selectors::matching::ElementSelectorFlags;
|
use selectors::matching::ElementSelectorFlags;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
#[cfg(feature = "servo")] use servo_atoms::Atom;
|
#[cfg(feature = "servo")] use servo_atoms::Atom;
|
||||||
|
@ -76,7 +76,7 @@ use properties::animated_properties::TransitionProperty;
|
|||||||
use properties::style_structs::Font;
|
use properties::style_structs::Font;
|
||||||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||||
use selector_parser::{AttrValue, ElementExt, PseudoClassStringArg};
|
use selector_parser::{AttrValue, ElementExt, PseudoClassStringArg};
|
||||||
use selectors::Element;
|
use selectors::{Element, OpaqueElement};
|
||||||
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
|
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
|
||||||
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
||||||
@ -1682,6 +1682,10 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
|
|||||||
impl<'le> ::selectors::Element for GeckoElement<'le> {
|
impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
|
|
||||||
|
fn opaque(&self) -> OpaqueElement {
|
||||||
|
OpaqueElement::new(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<Self> {
|
fn parent_element(&self) -> Option<Self> {
|
||||||
// FIXME(emilio): This will need to jump across if the parent node is a
|
// FIXME(emilio): This will need to jump across if the parent node is a
|
||||||
// shadow root to get the shadow host.
|
// shadow root to get the shadow host.
|
||||||
|
@ -9,7 +9,7 @@ use {Atom, CaseSensitivityExt, LocalName, Namespace};
|
|||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
||||||
use selectors::Element;
|
use selectors::{Element, OpaqueElement};
|
||||||
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
|
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
|
||||||
use selectors::matching::RelevantLinkStatus;
|
use selectors::matching::RelevantLinkStatus;
|
||||||
@ -258,6 +258,10 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||||||
self.element.is_link()
|
self.element.is_link()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn opaque(&self) -> OpaqueElement {
|
||||||
|
self.element.opaque()
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<Self> {
|
fn parent_element(&self) -> Option<Self> {
|
||||||
self.element.parent_element()
|
self.element.parent_element()
|
||||||
.map(|e| ElementWrapper::new(e, self.snapshot_map))
|
.map(|e| ElementWrapper::new(e, self.snapshot_map))
|
||||||
|
@ -10,7 +10,7 @@ use Atom;
|
|||||||
use bloom::StyleBloom;
|
use bloom::StyleBloom;
|
||||||
use context::{SelectorFlagsMap, SharedStyleContext};
|
use context::{SelectorFlagsMap, SharedStyleContext};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use selectors::context::NthIndexCache;
|
use selectors::NthIndexCache;
|
||||||
use sharing::{StyleSharingCandidate, StyleSharingTarget};
|
use sharing::{StyleSharingCandidate, StyleSharingTarget};
|
||||||
|
|
||||||
/// Determines whether a target and a candidate have compatible parents for sharing.
|
/// Determines whether a target and a candidate have compatible parents for sharing.
|
||||||
|
@ -75,7 +75,7 @@ use matching::MatchMethods;
|
|||||||
use owning_ref::OwningHandle;
|
use owning_ref::OwningHandle;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selectors::context::NthIndexCache;
|
use selectors::NthIndexCache;
|
||||||
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
||||||
use servo_arc::{Arc, NonZeroPtrMut};
|
use servo_arc::{Arc, NonZeroPtrMut};
|
||||||
use smallbitvec::SmallBitVec;
|
use smallbitvec::SmallBitVec;
|
||||||
|
@ -28,9 +28,10 @@ use properties::IS_LINK;
|
|||||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
||||||
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
|
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
|
||||||
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
||||||
|
use selectors::NthIndexCache;
|
||||||
use selectors::attr::NamespaceConstraint;
|
use selectors::attr::NamespaceConstraint;
|
||||||
use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
|
use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
|
||||||
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode, NthIndexCache};
|
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
|
||||||
use selectors::matching::VisitedHandlingMode;
|
use selectors::matching::VisitedHandlingMode;
|
||||||
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
|
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
|
||||||
use selectors::parser::{SelectorIter, SelectorMethods};
|
use selectors::parser::{SelectorIter, SelectorMethods};
|
||||||
|
Loading…
Reference in New Issue
Block a user