mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
style: Optimize [id=foo] as #foo in querySelector/All
This page seems to rely on this optimization being present. Optimizing it is straight-forward. Why do they do that instead of using the #foo syntax? Who knows. Differential Revision: https://phabricator.services.mozilla.com/D173148
This commit is contained in:
parent
536b3d603b
commit
7d12331626
2 changed files with 93 additions and 63 deletions
|
@ -7,13 +7,14 @@
|
|||
|
||||
use crate::context::QuirksMode;
|
||||
use crate::dom::{TDocument, TElement, TNode, TShadowRoot};
|
||||
use crate::selector_parser::SelectorImpl;
|
||||
use crate::invalidation::element::invalidation_map::Dependency;
|
||||
use crate::invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation};
|
||||
use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
|
||||
use crate::values::AtomIdent;
|
||||
use selectors::attr::CaseSensitivity;
|
||||
use selectors::matching::{self, MatchingContext, MatchingMode, NeedsSelectorFlags};
|
||||
use selectors::parser::{Combinator, Component, LocalName, SelectorImpl};
|
||||
use selectors::parser::{Combinator, Component, LocalName};
|
||||
use selectors::{Element, SelectorList};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
@ -376,6 +377,23 @@ where
|
|||
element.local_name() == &**chosen_name
|
||||
}
|
||||
|
||||
fn get_id(component: &Component<SelectorImpl>) -> Option<&AtomIdent> {
|
||||
use selectors::attr::AttrSelectorOperator;
|
||||
Some(match component {
|
||||
Component::ID(ref id) => id,
|
||||
Component::AttributeInNoNamespace { ref operator, ref local_name, ref value, .. } => {
|
||||
if *local_name != local_name!("id") {
|
||||
return None;
|
||||
}
|
||||
if *operator != AttrSelectorOperator::Equal {
|
||||
return None;
|
||||
}
|
||||
AtomIdent::cast(&value.0)
|
||||
},
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Fast paths for querySelector with a single simple selector.
|
||||
fn query_selector_single_query<E, Q>(
|
||||
root: E::ConcreteNode,
|
||||
|
@ -387,13 +405,11 @@ where
|
|||
E: TElement,
|
||||
Q: SelectorQuery<E>,
|
||||
{
|
||||
// TODO: Maybe we could implement a fast path for [name=""]?
|
||||
match *component {
|
||||
Component::ExplicitUniversalType => {
|
||||
collect_all_elements::<E, Q, _>(root, results, |_| true)
|
||||
},
|
||||
Component::ID(ref id) => {
|
||||
collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |_| true);
|
||||
},
|
||||
Component::Class(ref class) => {
|
||||
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
|
||||
collect_all_elements::<E, Q, _>(root, results, |element| {
|
||||
|
@ -405,16 +421,22 @@ where
|
|||
local_name_matches(element, local_name)
|
||||
})
|
||||
},
|
||||
ref other => {
|
||||
let id = match get_id(other) {
|
||||
Some(id) => id,
|
||||
// TODO(emilio): More fast paths?
|
||||
_ => return Err(()),
|
||||
None => return Err(()),
|
||||
};
|
||||
collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |_| true);
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum SimpleFilter<'a, Impl: SelectorImpl> {
|
||||
enum SimpleFilter<'a> {
|
||||
Class(&'a AtomIdent),
|
||||
LocalName(&'a LocalName<Impl>),
|
||||
LocalName(&'a LocalName<SelectorImpl>),
|
||||
}
|
||||
|
||||
/// Fast paths for a given selector query.
|
||||
|
@ -468,14 +490,29 @@ where
|
|||
|
||||
'component_loop: for component in &mut iter {
|
||||
match *component {
|
||||
Component::ID(ref id) => {
|
||||
Component::Class(ref class) => {
|
||||
if combinator.is_none() {
|
||||
// In the rightmost compound, just find descendants of
|
||||
// root that match the selector list with that id.
|
||||
simple_filter = Some(SimpleFilter::Class(class));
|
||||
}
|
||||
},
|
||||
Component::LocalName(ref local_name) => {
|
||||
if combinator.is_none() {
|
||||
// Prefer to look at class rather than local-name if
|
||||
// both are present.
|
||||
if let Some(SimpleFilter::Class(..)) = simple_filter {
|
||||
continue;
|
||||
}
|
||||
simple_filter = Some(SimpleFilter::LocalName(local_name));
|
||||
}
|
||||
},
|
||||
ref other => {
|
||||
if let Some(id) = get_id(other) {
|
||||
if combinator.is_none() {
|
||||
// In the rightmost compound, just find descendants of root that match
|
||||
// the selector list with that id.
|
||||
collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |e| {
|
||||
matching::matches_selector_list(selector_list, &e, matching_context)
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -521,23 +558,8 @@ where
|
|||
}
|
||||
|
||||
return Ok(());
|
||||
},
|
||||
Component::Class(ref class) => {
|
||||
if combinator.is_none() {
|
||||
simple_filter = Some(SimpleFilter::Class(class));
|
||||
}
|
||||
},
|
||||
Component::LocalName(ref local_name) => {
|
||||
if combinator.is_none() {
|
||||
// Prefer to look at class rather than local-name if
|
||||
// both are present.
|
||||
if let Some(SimpleFilter::Class(..)) = simple_filter {
|
||||
continue;
|
||||
}
|
||||
simple_filter = Some(SimpleFilter::LocalName(local_name));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -380,6 +380,14 @@ impl AtomIdent {
|
|||
callback(&*atom)
|
||||
})
|
||||
}
|
||||
|
||||
/// Cast an atom ref to an AtomIdent ref.
|
||||
#[inline]
|
||||
pub fn cast<'a>(atom: &'a Atom) -> &'a Self {
|
||||
let ptr = atom as *const _ as *const Self;
|
||||
// safety: repr(transparent)
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue