style: Avoid some allocations in selector serialization.

The allocations in display_to_css_identifier show up in the profiles of
bug 1675628.

Differential Revision: https://phabricator.services.mozilla.com/D97856
This commit is contained in:
Emilio Cobos Álvarez 2020-11-22 01:02:22 +00:00
parent 4ea378a6ae
commit 9f40b9ba38
19 changed files with 220 additions and 114 deletions

View file

@ -20,7 +20,8 @@ use crate::selector_parser::{AttrValue, Lang, PseudoElement, SelectorImpl};
use crate::shared_lock::{Locked, SharedRwLock}; use crate::shared_lock::{Locked, SharedRwLock};
use crate::stylist::CascadeData; use crate::stylist::CascadeData;
use crate::traversal_flags::TraversalFlags; use crate::traversal_flags::TraversalFlags;
use crate::{Atom, LocalName, Namespace, WeakAtom}; use crate::values::AtomIdent;
use crate::{LocalName, Namespace, WeakAtom};
use atomic_refcell::{AtomicRef, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefMut};
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode}; use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
use selectors::sink::Push; use selectors::sink::Push;
@ -121,7 +122,7 @@ pub trait TDocument: Sized + Copy + Clone {
/// return an empty slice. /// return an empty slice.
fn elements_with_id<'a>( fn elements_with_id<'a>(
&self, &self,
_id: &Atom, _id: &AtomIdent,
) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()> ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
where where
Self: 'a, Self: 'a,
@ -344,7 +345,7 @@ pub trait TShadowRoot: Sized + Copy + Clone + Debug + PartialEq {
/// return an empty slice. /// return an empty slice.
fn elements_with_id<'a>( fn elements_with_id<'a>(
&self, &self,
_id: &Atom, _id: &AtomIdent,
) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()> ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
where where
Self: 'a, Self: 'a,
@ -520,20 +521,20 @@ pub trait TElement:
/// Internal iterator for the classes of this element. /// Internal iterator for the classes of this element.
fn each_class<F>(&self, callback: F) fn each_class<F>(&self, callback: F)
where where
F: FnMut(&Atom); F: FnMut(&AtomIdent);
/// Internal iterator for the part names of this element. /// Internal iterator for the part names of this element.
fn each_part<F>(&self, _callback: F) fn each_part<F>(&self, _callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
} }
/// Internal iterator for the part names that this element exports for a /// Internal iterator for the part names that this element exports for a
/// given part name. /// given part name.
fn each_exported_part<F>(&self, _name: &Atom, _callback: F) fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
} }

View file

@ -10,7 +10,7 @@ use crate::dom::{TDocument, TElement, TNode, TShadowRoot};
use crate::invalidation::element::invalidation_map::Dependency; use crate::invalidation::element::invalidation_map::Dependency;
use crate::invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation}; use crate::invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation};
use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector}; use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
use crate::Atom; use crate::values::AtomIdent;
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::matching::{self, MatchingContext, MatchingMode}; use selectors::matching::{self, MatchingContext, MatchingMode};
use selectors::parser::{Combinator, Component, LocalName, SelectorImpl}; use selectors::parser::{Combinator, Component, LocalName, SelectorImpl};
@ -276,7 +276,7 @@ where
/// or shadow root that `root` is connected to. /// or shadow root that `root` is connected to.
fn fast_connected_elements_with_id<'a, N>( fn fast_connected_elements_with_id<'a, N>(
root: N, root: N,
id: &Atom, id: &AtomIdent,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
) -> Result<&'a [N::ConcreteElement], ()> ) -> Result<&'a [N::ConcreteElement], ()>
where where
@ -305,7 +305,7 @@ where
/// Collects elements with a given id under `root`, that pass `filter`. /// Collects elements with a given id under `root`, that pass `filter`.
fn collect_elements_with_id<E, Q, F>( fn collect_elements_with_id<E, Q, F>(
root: E::ConcreteNode, root: E::ConcreteNode,
id: &Atom, id: &AtomIdent,
results: &mut Q::Output, results: &mut Q::Output,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
mut filter: F, mut filter: F,
@ -398,7 +398,7 @@ where
} }
enum SimpleFilter<'a, Impl: SelectorImpl> { enum SimpleFilter<'a, Impl: SelectorImpl> {
Class(&'a Atom), Class(&'a AtomIdent),
LocalName(&'a LocalName<Impl>), LocalName(&'a LocalName<Impl>),
} }

View file

@ -11,7 +11,7 @@ use crate::invalidation::element::document_state::InvalidationMatchingData;
use crate::selector_parser::{Direction, SelectorParser}; use crate::selector_parser::{Direction, SelectorParser};
use crate::str::starts_with_ignore_ascii_case; use crate::str::starts_with_ignore_ascii_case;
use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use crate::values::serialize_atom_identifier; use crate::values::{AtomIdent, AtomString};
use cssparser::{BasicParseError, BasicParseErrorKind, Parser}; use cssparser::{BasicParseError, BasicParseErrorKind, Parser};
use cssparser::{CowRcStr, SourceLocation, ToCss, Token}; use cssparser::{CowRcStr, SourceLocation, ToCss, Token};
use selectors::parser::{SelectorParseErrorKind, ParseErrorRecovery}; use selectors::parser::{SelectorParseErrorKind, ParseErrorRecovery};
@ -39,7 +39,7 @@ bitflags! {
} }
/// The type used to store the language argument to the `:lang` pseudo-class. /// The type used to store the language argument to the `:lang` pseudo-class.
pub type Lang = Atom; pub type Lang = AtomIdent;
macro_rules! pseudo_class_name { macro_rules! pseudo_class_name {
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => {
@ -77,7 +77,7 @@ impl ToCss for NonTSPseudoClass {
$(NonTSPseudoClass::$name => concat!(":", $css),)* $(NonTSPseudoClass::$name => concat!(":", $css),)*
NonTSPseudoClass::Lang(ref s) => { NonTSPseudoClass::Lang(ref s) => {
dest.write_str(":lang(")?; dest.write_str(":lang(")?;
serialize_atom_identifier(s, dest)?; s.to_css(dest)?;
return dest.write_char(')'); return dest.write_char(')');
}, },
NonTSPseudoClass::MozLocaleDir(ref dir) => { NonTSPseudoClass::MozLocaleDir(ref dir) => {
@ -270,12 +270,10 @@ pub struct SelectorImpl;
impl ::selectors::SelectorImpl for SelectorImpl { impl ::selectors::SelectorImpl for SelectorImpl {
type ExtraMatchingData = InvalidationMatchingData; type ExtraMatchingData = InvalidationMatchingData;
type AttrValue = Atom; type AttrValue = AtomString;
type Identifier = Atom; type Identifier = AtomIdent;
type ClassName = Atom; type LocalName = AtomIdent;
type PartName = Atom; type NamespacePrefix = AtomIdent;
type LocalName = Atom;
type NamespacePrefix = Atom;
type NamespaceUrl = Namespace; type NamespaceUrl = Namespace;
type BorrowedNamespaceUrl = WeakNamespace; type BorrowedNamespaceUrl = WeakNamespace;
type BorrowedLocalName = WeakAtom; type BorrowedLocalName = WeakAtom;
@ -386,7 +384,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
let pseudo_class = match_ignore_ascii_case! { &name, let pseudo_class = match_ignore_ascii_case! { &name,
"lang" => { "lang" => {
let name = parser.expect_ident_or_string()?; let name = parser.expect_ident_or_string()?;
NonTSPseudoClass::Lang(Atom::from(name.as_ref())) NonTSPseudoClass::Lang(Lang::from(name.as_ref()))
}, },
"-moz-locale-dir" => { "-moz-locale-dir" => {
NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?) NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?)
@ -475,7 +473,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
self.namespaces.default.clone() self.namespaces.default.clone()
} }
fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> { fn namespace_for_prefix(&self, prefix: &AtomIdent) -> Option<Namespace> {
self.namespaces.prefixes.get(prefix).cloned() self.namespaces.prefixes.get(prefix).cloned()
} }
} }

View file

@ -14,7 +14,10 @@ use crate::gecko_bindings::structs::ServoElementSnapshot;
use crate::gecko_bindings::structs::ServoElementSnapshotFlags as Flags; use crate::gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
use crate::gecko_bindings::structs::ServoElementSnapshotTable; use crate::gecko_bindings::structs::ServoElementSnapshotTable;
use crate::invalidation::element::element_wrapper::ElementSnapshot; use crate::invalidation::element::element_wrapper::ElementSnapshot;
use crate::selector_parser::AttrValue;
use crate::string_cache::{Atom, Namespace}; use crate::string_cache::{Atom, Namespace};
use crate::values::{AtomIdent, AtomString};
use crate::LocalName;
use crate::WeakAtom; use crate::WeakAtom;
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator};
use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::attr::{CaseSensitivity, NamespaceConstraint};
@ -74,10 +77,10 @@ impl GeckoElementSnapshot {
#[inline] #[inline]
pub fn each_attr_changed<F>(&self, mut callback: F) pub fn each_attr_changed<F>(&self, mut callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
for attr in self.mChangedAttrNames.iter() { for attr in self.mChangedAttrNames.iter() {
unsafe { Atom::with(attr.mRawPtr, &mut callback) } unsafe { AtomIdent::with(attr.mRawPtr, &mut callback) }
} }
} }
@ -85,8 +88,8 @@ impl GeckoElementSnapshot {
pub fn attr_matches( pub fn attr_matches(
&self, &self,
ns: &NamespaceConstraint<&Namespace>, ns: &NamespaceConstraint<&Namespace>,
local_name: &Atom, local_name: &LocalName,
operation: &AttrSelectorOperation<&Atom>, operation: &AttrSelectorOperation<&AttrValue>,
) -> bool { ) -> bool {
unsafe { unsafe {
match *operation { match *operation {
@ -188,7 +191,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
} }
#[inline] #[inline]
fn is_part(&self, name: &Atom) -> bool { fn is_part(&self, name: &AtomIdent) -> bool {
let attr = match snapshot_helpers::find_attr(&*self.mAttrs, &atom!("part")) { let attr = match snapshot_helpers::find_attr(&*self.mAttrs, &atom!("part")) {
Some(attr) => attr, Some(attr) => attr,
None => return false, None => return false,
@ -198,12 +201,12 @@ impl ElementSnapshot for GeckoElementSnapshot {
} }
#[inline] #[inline]
fn imported_part(&self, name: &Atom) -> Option<Atom> { fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
snapshot_helpers::imported_part(&*self.mAttrs, name) snapshot_helpers::imported_part(&*self.mAttrs, name)
} }
#[inline] #[inline]
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool { fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
if !self.has_any(Flags::MaybeClass) { if !self.has_any(Flags::MaybeClass) {
return false; return false;
} }
@ -214,7 +217,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
#[inline] #[inline]
fn each_class<F>(&self, callback: F) fn each_class<F>(&self, callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
if !self.has_any(Flags::MaybeClass) { if !self.has_any(Flags::MaybeClass) {
return; return;
@ -224,12 +227,12 @@ impl ElementSnapshot for GeckoElementSnapshot {
} }
#[inline] #[inline]
fn lang_attr(&self) -> Option<Atom> { fn lang_attr(&self) -> Option<AtomString> {
let ptr = unsafe { bindings::Gecko_SnapshotLangValue(self) }; let ptr = unsafe { bindings::Gecko_SnapshotLangValue(self) };
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
Some(unsafe { Atom::from_addrefed(ptr) }) Some(AtomString(unsafe { Atom::from_addrefed(ptr) }))
} }
} }
} }

View file

@ -6,7 +6,9 @@
use crate::gecko_bindings::bindings; use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs::{self, nsAtom}; use crate::gecko_bindings::structs::{self, nsAtom};
use crate::string_cache::{Atom, WeakAtom}; use crate::string_cache::WeakAtom;
use crate::values::AtomIdent;
use crate::Atom;
use crate::CaseSensitivityExt; use crate::CaseSensitivityExt;
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
@ -85,8 +87,8 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> {
#[inline(always)] #[inline(always)]
pub(super) fn each_exported_part( pub(super) fn each_exported_part(
attrs: &[structs::AttrArray_InternalAttr], attrs: &[structs::AttrArray_InternalAttr],
name: &Atom, name: &AtomIdent,
mut callback: impl FnMut(&Atom), mut callback: impl FnMut(&AtomIdent),
) { ) {
let attr = match find_attr(attrs, &atom!("exportparts")) { let attr = match find_attr(attrs, &atom!("exportparts")) {
Some(attr) => attr, Some(attr) => attr,
@ -100,7 +102,7 @@ pub(super) fn each_exported_part(
unsafe { unsafe {
for atom in std::slice::from_raw_parts(atoms, length) { for atom in std::slice::from_raw_parts(atoms, length) {
Atom::with(*atom, &mut callback) AtomIdent::with(*atom, &mut callback)
} }
} }
} }
@ -108,21 +110,21 @@ pub(super) fn each_exported_part(
#[inline(always)] #[inline(always)]
pub(super) fn imported_part( pub(super) fn imported_part(
attrs: &[structs::AttrArray_InternalAttr], attrs: &[structs::AttrArray_InternalAttr],
name: &Atom, name: &AtomIdent,
) -> Option<Atom> { ) -> Option<AtomIdent> {
let attr = find_attr(attrs, &atom!("exportparts"))?; let attr = find_attr(attrs, &atom!("exportparts"))?;
let atom = unsafe { bindings::Gecko_Element_ImportedPart(attr, name.as_ptr()) }; let atom = unsafe { bindings::Gecko_Element_ImportedPart(attr, name.as_ptr()) };
if atom.is_null() { if atom.is_null() {
return None; return None;
} }
Some(unsafe { Atom::from_raw(atom) }) Some(AtomIdent(unsafe { Atom::from_raw(atom) }))
} }
/// Given a class or part name, a case sensitivity, and an array of attributes, /// Given a class or part name, a case sensitivity, and an array of attributes,
/// returns whether the attribute has that name. /// returns whether the attribute has that name.
#[inline(always)] #[inline(always)]
pub fn has_class_or_part( pub fn has_class_or_part(
name: &Atom, name: &AtomIdent,
case_sensitivity: CaseSensitivity, case_sensitivity: CaseSensitivity,
attr: &structs::nsAttrValue, attr: &structs::nsAttrValue,
) -> bool { ) -> bool {
@ -147,15 +149,15 @@ pub fn has_class_or_part(
#[inline(always)] #[inline(always)]
pub fn each_class_or_part<F>(attr: &structs::nsAttrValue, mut callback: F) pub fn each_class_or_part<F>(attr: &structs::nsAttrValue, mut callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
unsafe { unsafe {
match get_class_or_part_from_attr(attr) { match get_class_or_part_from_attr(attr) {
Class::None => {}, Class::None => {},
Class::One(atom) => Atom::with(atom, callback), Class::One(atom) => AtomIdent::with(atom, callback),
Class::More(atoms) => { Class::More(atoms) => {
for atom in atoms { for atom in atoms {
Atom::with(atom.mRawPtr, &mut callback) AtomIdent::with(atom.mRawPtr, &mut callback)
} }
}, },
} }

View file

@ -70,7 +70,9 @@ use crate::stylist::CascadeData;
use crate::values::computed::font::GenericFontFamily; use crate::values::computed::font::GenericFontFamily;
use crate::values::computed::Length; use crate::values::computed::Length;
use crate::values::specified::length::FontBaseSize; use crate::values::specified::length::FontBaseSize;
use crate::values::{AtomIdent, AtomString};
use crate::CaseSensitivityExt; use crate::CaseSensitivityExt;
use crate::LocalName;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator};
use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::attr::{CaseSensitivity, NamespaceConstraint};
@ -130,7 +132,7 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
} }
#[inline] #[inline]
fn elements_with_id<'a>(&self, id: &Atom) -> Result<&'a [GeckoElement<'ld>], ()> fn elements_with_id<'a>(&self, id: &AtomIdent) -> Result<&'a [GeckoElement<'ld>], ()>
where where
Self: 'a, Self: 'a,
{ {
@ -186,7 +188,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
} }
#[inline] #[inline]
fn elements_with_id<'a>(&self, id: &Atom) -> Result<&'a [GeckoElement<'lr>], ()> fn elements_with_id<'a>(&self, id: &AtomIdent) -> Result<&'a [GeckoElement<'lr>], ()>
where where
Self: 'a, Self: 'a,
{ {
@ -801,7 +803,7 @@ impl<'le> GeckoElement<'le> {
return false; return false;
} }
let host = self.containing_shadow_host().unwrap(); let host = self.containing_shadow_host().unwrap();
host.is_svg_element() && host.local_name() == &*local_name!("use") host.is_svg_element() && host.local_name() == &**local_name!("use")
} }
fn css_transitions_info(&self) -> FxHashMap<LonghandId, Arc<AnimationValue>> { fn css_transitions_info(&self) -> FxHashMap<LonghandId, Arc<AnimationValue>> {
@ -1270,7 +1272,7 @@ impl<'le> TElement for GeckoElement<'le> {
} }
#[inline] #[inline]
fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool { fn has_attr(&self, namespace: &Namespace, attr: &AtomIdent) -> bool {
unsafe { bindings::Gecko_HasAttr(self.0, namespace.0.as_ptr(), attr.as_ptr()) } unsafe { bindings::Gecko_HasAttr(self.0, namespace.0.as_ptr(), attr.as_ptr()) }
} }
@ -1297,7 +1299,7 @@ impl<'le> TElement for GeckoElement<'le> {
fn each_class<F>(&self, callback: F) fn each_class<F>(&self, callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
let attr = match self.get_class_attr() { let attr = match self.get_class_attr() {
Some(c) => c, Some(c) => c,
@ -1308,16 +1310,16 @@ impl<'le> TElement for GeckoElement<'le> {
} }
#[inline] #[inline]
fn each_exported_part<F>(&self, name: &Atom, callback: F) fn each_exported_part<F>(&self, name: &AtomIdent, callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
snapshot_helpers::each_exported_part(self.attrs(), name, callback) snapshot_helpers::each_exported_part(self.attrs(), name, callback)
} }
fn each_part<F>(&self, callback: F) fn each_part<F>(&self, callback: F)
where where
F: FnMut(&Atom), F: FnMut(&AtomIdent),
{ {
let attr = match self.get_part_attr() { let attr = match self.get_part_attr() {
Some(c) => c, Some(c) => c,
@ -1615,7 +1617,7 @@ impl<'le> TElement for GeckoElement<'le> {
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
Some(unsafe { Atom::from_addrefed(ptr) }) Some(AtomString(unsafe { Atom::from_addrefed(ptr) }))
} }
} }
@ -1623,8 +1625,8 @@ impl<'le> TElement for GeckoElement<'le> {
// Gecko supports :lang() from CSS Selectors 3, which only accepts a // Gecko supports :lang() from CSS Selectors 3, which only accepts a
// single language tag, and which performs simple dash-prefix matching // single language tag, and which performs simple dash-prefix matching
// on it. // on it.
let override_lang_ptr = match &override_lang { let override_lang_ptr = match override_lang {
&Some(Some(ref atom)) => atom.as_ptr(), Some(Some(ref atom)) => atom.as_ptr(),
_ => ptr::null_mut(), _ => ptr::null_mut(),
}; };
unsafe { unsafe {
@ -1638,7 +1640,7 @@ impl<'le> TElement for GeckoElement<'le> {
} }
fn is_html_document_body_element(&self) -> bool { fn is_html_document_body_element(&self) -> bool {
if self.local_name() != &*local_name!("body") { if self.local_name() != &**local_name!("body") {
return false; return false;
} }
@ -1895,8 +1897,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
fn attr_matches( fn attr_matches(
&self, &self,
ns: &NamespaceConstraint<&Namespace>, ns: &NamespaceConstraint<&Namespace>,
local_name: &Atom, local_name: &LocalName,
operation: &AttrSelectorOperation<&Atom>, operation: &AttrSelectorOperation<&AttrValue>,
) -> bool { ) -> bool {
unsafe { unsafe {
match *operation { match *operation {
@ -2180,7 +2182,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
} }
#[inline] #[inline]
fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool { fn has_id(&self, id: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
if !self.has_id() { if !self.has_id() {
return false; return false;
} }
@ -2194,7 +2196,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
} }
#[inline] #[inline]
fn is_part(&self, name: &Atom) -> bool { fn is_part(&self, name: &AtomIdent) -> bool {
let attr = match self.get_part_attr() { let attr = match self.get_part_attr() {
Some(c) => c, Some(c) => c,
None => return false, None => return false,
@ -2204,12 +2206,12 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
} }
#[inline] #[inline]
fn imported_part(&self, name: &Atom) -> Option<Atom> { fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
snapshot_helpers::imported_part(self.attrs(), name) snapshot_helpers::imported_part(self.attrs(), name)
} }
#[inline(always)] #[inline(always)]
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool { fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
let attr = match self.get_class_attr() { let attr = match self.get_class_attr() {
Some(c) => c, Some(c) => c,
None => return false, None => return false,

View file

@ -42,12 +42,6 @@ pub mod namespace;
pub use self::namespace::{Namespace, WeakNamespace}; pub use self::namespace::{Namespace, WeakNamespace};
macro_rules! local_name {
($s:tt) => {
atom!($s)
};
}
/// A handle to a Gecko atom. This is a type that can represent either: /// A handle to a Gecko atom. This is a type that can represent either:
/// ///
/// * A strong reference to a dynamic atom (an `nsAtom` pointer), in which case /// * A strong reference to a dynamic atom (an `nsAtom` pointer), in which case

View file

@ -47,18 +47,9 @@ impl PrecomputedHash for Namespace {
} }
/// A Gecko WeakNamespace is a wrapped WeakAtom. /// A Gecko WeakNamespace is a wrapped WeakAtom.
#[derive(Hash)] #[derive(Hash, Deref)]
pub struct WeakNamespace(WeakAtom); pub struct WeakNamespace(WeakAtom);
impl Deref for WeakNamespace {
type Target = WeakAtom;
#[inline]
fn deref(&self) -> &WeakAtom {
&self.0
}
}
impl Deref for Namespace { impl Deref for Namespace {
type Target = WeakNamespace; type Target = WeakNamespace;

View file

@ -9,7 +9,8 @@ use crate::dom::TElement;
use crate::element_state::ElementState; use crate::element_state::ElementState;
use crate::selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl}; use crate::selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl};
use crate::selector_parser::{Snapshot, SnapshotMap}; use crate::selector_parser::{Snapshot, SnapshotMap};
use crate::{Atom, CaseSensitivityExt, LocalName, Namespace, WeakAtom}; use crate::values::AtomIdent;
use crate::{CaseSensitivityExt, LocalName, Namespace, WeakAtom};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint}; use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext}; use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::{Element, OpaqueElement}; use selectors::{Element, OpaqueElement};
@ -56,20 +57,20 @@ pub trait ElementSnapshot: Sized {
/// Whether this snapshot contains the class `name`. Should only be called /// Whether this snapshot contains the class `name`. Should only be called
/// if `has_attrs()` returns true. /// if `has_attrs()` returns true.
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool; fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool;
/// Whether this snapshot represents the part named `name`. Should only be /// Whether this snapshot represents the part named `name`. Should only be
/// called if `has_attrs()` returns true. /// called if `has_attrs()` returns true.
fn is_part(&self, name: &Atom) -> bool; fn is_part(&self, name: &AtomIdent) -> bool;
/// See Element::imported_part. /// See Element::imported_part.
fn imported_part(&self, name: &Atom) -> Option<Atom>; fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent>;
/// A callback that should be called for each class of the snapshot. Should /// A callback that should be called for each class of the snapshot. Should
/// only be called if `has_attrs()` returns true. /// only be called if `has_attrs()` returns true.
fn each_class<F>(&self, _: F) fn each_class<F>(&self, _: F)
where where
F: FnMut(&Atom); F: FnMut(&AtomIdent);
/// The `xml:lang=""` or `lang=""` attribute value per this snapshot. /// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
fn lang_attr(&self) -> Option<AttrValue>; fn lang_attr(&self) -> Option<AttrValue>;
@ -361,7 +362,7 @@ where
} }
} }
fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool { fn has_id(&self, id: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
match self.snapshot() { match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => snapshot Some(snapshot) if snapshot.has_attrs() => snapshot
.id_attr() .id_attr()
@ -370,21 +371,21 @@ where
} }
} }
fn is_part(&self, name: &Atom) -> bool { fn is_part(&self, name: &AtomIdent) -> bool {
match self.snapshot() { match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => snapshot.is_part(name), Some(snapshot) if snapshot.has_attrs() => snapshot.is_part(name),
_ => self.element.is_part(name), _ => self.element.is_part(name),
} }
} }
fn imported_part(&self, name: &Atom) -> Option<Atom> { fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
match self.snapshot() { match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => snapshot.imported_part(name), Some(snapshot) if snapshot.has_attrs() => snapshot.imported_part(name),
_ => self.element.imported_part(name), _ => self.element.imported_part(name),
} }
} }
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool { fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
match self.snapshot() { match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity), Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity),
_ => self.element.has_class(name, case_sensitivity), _ => self.element.has_class(name, case_sensitivity),

View file

@ -478,7 +478,7 @@ impl<'a> SelectorVisitor for SelectorDependencyCollector<'a> {
Component::Class(..) => &mut self.map.class_to_selector, Component::Class(..) => &mut self.map.class_to_selector,
_ => unreachable!(), _ => unreachable!(),
}; };
let entry = match map.try_entry(atom.clone(), self.quirks_mode) { let entry = match map.try_entry(atom.0.clone(), self.quirks_mode) {
Ok(entry) => entry, Ok(entry) => entry,
Err(err) => { Err(err) => {
*self.alloc_error = Some(err); *self.alloc_error = Some(err);

View file

@ -216,13 +216,13 @@ where
// TODO(emilio): Do this more efficiently! // TODO(emilio): Do this more efficiently!
snapshot.each_class(|c| { snapshot.each_class(|c| {
if !element.has_class(c, CaseSensitivity::CaseSensitive) { if !element.has_class(c, CaseSensitivity::CaseSensitive) {
classes_removed.push(c.clone()) classes_removed.push(c.0.clone())
} }
}); });
element.each_class(|c| { element.each_class(|c| {
if !snapshot.has_class(c, CaseSensitivity::CaseSensitive) { if !snapshot.has_class(c, CaseSensitivity::CaseSensitive) {
classes_added.push(c.clone()) classes_added.push(c.0.clone())
} }
}) })
} }

View file

@ -17,6 +17,7 @@ use crate::selector_parser::{SelectorImpl, Snapshot, SnapshotMap};
use crate::shared_lock::SharedRwLockReadGuard; use crate::shared_lock::SharedRwLockReadGuard;
use crate::stylesheets::{CssRule, StylesheetInDocument}; use crate::stylesheets::{CssRule, StylesheetInDocument};
use crate::stylesheets::{EffectiveRules, EffectiveRulesIterator}; use crate::stylesheets::{EffectiveRules, EffectiveRulesIterator};
use crate::values::AtomIdent;
use crate::Atom; use crate::Atom;
use crate::LocalName as SelectorLocalName; use crate::LocalName as SelectorLocalName;
use selectors::parser::{Component, LocalName, Selector}; use selectors::parser::{Component, LocalName, Selector};
@ -43,9 +44,9 @@ pub enum RuleChangeKind {
#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] #[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
enum Invalidation { enum Invalidation {
/// An element with a given id. /// An element with a given id.
ID(Atom), ID(AtomIdent),
/// An element with a given class name. /// An element with a given class name.
Class(Atom), Class(AtomIdent),
/// An element with a given local name. /// An element with a given local name.
LocalName { LocalName {
name: SelectorLocalName, name: SelectorLocalName,
@ -468,14 +469,14 @@ impl StylesheetInvalidationSet {
) -> bool { ) -> bool {
match invalidation { match invalidation {
Invalidation::Class(c) => { Invalidation::Class(c) => {
let entry = match self.classes.try_entry(c, quirks_mode) { let entry = match self.classes.try_entry(c.0, quirks_mode) {
Ok(e) => e, Ok(e) => e,
Err(..) => return false, Err(..) => return false,
}; };
*entry.or_insert(InvalidationKind::None) |= kind; *entry.or_insert(InvalidationKind::None) |= kind;
}, },
Invalidation::ID(i) => { Invalidation::ID(i) => {
let entry = match self.ids.try_entry(i, quirks_mode) { let entry = match self.ids.try_entry(i.0, quirks_mode) {
Ok(e) => e, Ok(e) => e,
Err(..) => return false, Err(..) => return false,
}; };

View file

@ -131,10 +131,10 @@ pub use crate::gecko_string_cache as string_cache;
pub use crate::gecko_string_cache::Atom; pub use crate::gecko_string_cache::Atom;
/// The namespace prefix type for Gecko, which is just an atom. /// The namespace prefix type for Gecko, which is just an atom.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type Prefix = crate::gecko_string_cache::Atom; pub type Prefix = crate::values::AtomIdent;
/// The local name of an element for Gecko, which is just an atom. /// The local name of an element for Gecko, which is just an atom.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type LocalName = crate::gecko_string_cache::Atom; pub type LocalName = crate::values::AtomIdent;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub use crate::gecko_string_cache::Namespace; pub use crate::gecko_string_cache::Namespace;

View file

@ -133,3 +133,10 @@ macro_rules! profiler_label {
macro_rules! profiler_label { macro_rules! profiler_label {
($label_type:ident) => {}; ($label_type:ident) => {};
} }
#[cfg(feature = "gecko")]
macro_rules! local_name {
($s:tt) => {
$crate::values::AtomIdent(atom!($s))
};
}

View file

@ -13,7 +13,6 @@ use crate::selector_parser::PseudoElement;
use crate::shared_lock::Locked; use crate::shared_lock::Locked;
use crate::stylesheets::Origin; use crate::stylesheets::Origin;
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist}; use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
use crate::Atom;
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode}; use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
use servo_arc::ArcBorrow; use servo_arc::ArcBorrow;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -43,7 +42,7 @@ pub fn containing_shadow_ignoring_svg_use<E: TElement>(
loop { loop {
let host = shadow.host(); let host = shadow.host();
let host_is_svg_use_element = let host_is_svg_use_element =
host.is_svg_element() && host.local_name() == &*local_name!("use"); host.is_svg_element() && host.local_name() == &**local_name!("use");
if !host_is_svg_use_element { if !host_is_svg_use_element {
return Some(shadow); return Some(shadow);
} }
@ -319,7 +318,7 @@ where
}; };
hash_target.each_part(|part| { hash_target.each_part(|part| {
if let Some(part_rules) = part_rules.get(part) { if let Some(part_rules) = part_rules.get(&part.0) {
collector.collect_rules_in_list(part_rules, cascade_level); collector.collect_rules_in_list(part_rules, cascade_level);
} }
}); });
@ -377,7 +376,7 @@ where
let mut shadow_cascade_order = ShadowCascadeOrder::for_innermost_containing_tree(); let mut shadow_cascade_order = ShadowCascadeOrder::for_innermost_containing_tree();
let mut parts = SmallVec::<[Atom; 3]>::new(); let mut parts = SmallVec::<[_; 3]>::new();
self.rule_hash_target.each_part(|p| parts.push(p.clone())); self.rule_hash_target.each_part(|p| parts.push(p.clone()));
loop { loop {
@ -405,7 +404,7 @@ where
}; };
self.in_tree(containing_host, |collector| { self.in_tree(containing_host, |collector| {
for p in &parts { for p in &parts {
if let Some(part_rules) = part_rules.get(p) { if let Some(part_rules) = part_rules.get(&p.0) {
collector.collect_rules_in_list(part_rules, cascade_level); collector.collect_rules_in_list(part_rules, cascade_level);
} }
} }

View file

@ -73,7 +73,7 @@ use crate::properties::ComputedValues;
use crate::rule_tree::StrongRuleNode; use crate::rule_tree::StrongRuleNode;
use crate::style_resolver::{PrimaryStyle, ResolvedElementStyles}; use crate::style_resolver::{PrimaryStyle, ResolvedElementStyles};
use crate::stylist::Stylist; use crate::stylist::Stylist;
use crate::Atom; use crate::values::AtomIdent;
use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use owning_ref::OwningHandle; use owning_ref::OwningHandle;
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode}; use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
@ -126,13 +126,13 @@ pub struct ValidationData {
/// ///
/// TODO(emilio): Maybe check whether rules for these classes apply to the /// TODO(emilio): Maybe check whether rules for these classes apply to the
/// element? /// element?
class_list: Option<SmallVec<[Atom; 5]>>, class_list: Option<SmallVec<[AtomIdent; 5]>>,
/// The part list of this element. /// The part list of this element.
/// ///
/// TODO(emilio): Maybe check whether rules with these part names apply to /// TODO(emilio): Maybe check whether rules with these part names apply to
/// the element? /// the element?
part_list: Option<SmallVec<[Atom; 5]>>, part_list: Option<SmallVec<[AtomIdent; 5]>>,
/// The list of presentational attributes of the element. /// The list of presentational attributes of the element.
pres_hints: Option<SmallVec<[ApplicableDeclarationBlock; 5]>>, pres_hints: Option<SmallVec<[ApplicableDeclarationBlock; 5]>>,
@ -168,7 +168,7 @@ impl ValidationData {
} }
/// Get or compute the part-list associated with this element. /// Get or compute the part-list associated with this element.
pub fn part_list<E>(&mut self, element: E) -> &[Atom] pub fn part_list<E>(&mut self, element: E) -> &[AtomIdent]
where where
E: TElement, E: TElement,
{ {
@ -176,7 +176,7 @@ impl ValidationData {
return &[]; return &[];
} }
self.part_list.get_or_insert_with(|| { self.part_list.get_or_insert_with(|| {
let mut list = SmallVec::<[Atom; 5]>::new(); let mut list = SmallVec::<[_; 5]>::new();
element.each_part(|p| list.push(p.clone())); element.each_part(|p| list.push(p.clone()));
// See below for the reasoning. // See below for the reasoning.
if !list.spilled() { if !list.spilled() {
@ -187,12 +187,12 @@ impl ValidationData {
} }
/// Get or compute the class-list associated with this element. /// Get or compute the class-list associated with this element.
pub fn class_list<E>(&mut self, element: E) -> &[Atom] pub fn class_list<E>(&mut self, element: E) -> &[AtomIdent]
where where
E: TElement, E: TElement,
{ {
self.class_list.get_or_insert_with(|| { self.class_list.get_or_insert_with(|| {
let mut list = SmallVec::<[Atom; 5]>::new(); let mut list = SmallVec::<[_; 5]>::new();
element.each_class(|c| list.push(c.clone())); element.each_class(|c| list.push(c.clone()));
// Assuming there are a reasonable number of classes (we use the // Assuming there are a reasonable number of classes (we use the
// inline capacity as "reasonable number"), sort them to so that // inline capacity as "reasonable number"), sort them to so that
@ -294,12 +294,12 @@ impl<E: TElement> Deref for StyleSharingCandidate<E> {
impl<E: TElement> StyleSharingCandidate<E> { impl<E: TElement> StyleSharingCandidate<E> {
/// Get the classlist of this candidate. /// Get the classlist of this candidate.
fn class_list(&mut self) -> &[Atom] { fn class_list(&mut self) -> &[AtomIdent] {
self.validation_data.class_list(self.element) self.validation_data.class_list(self.element)
} }
/// Get the part list of this candidate. /// Get the part list of this candidate.
fn part_list(&mut self) -> &[Atom] { fn part_list(&mut self) -> &[AtomIdent] {
self.validation_data.part_list(self.element) self.validation_data.part_list(self.element)
} }
@ -361,11 +361,11 @@ impl<E: TElement> StyleSharingTarget<E> {
} }
} }
fn class_list(&mut self) -> &[Atom] { fn class_list(&mut self) -> &[AtomIdent] {
self.validation_data.class_list(self.element) self.validation_data.class_list(self.element)
} }
fn part_list(&mut self) -> &[Atom] { fn part_list(&mut self) -> &[AtomIdent] {
self.validation_data.part_list(self.element) self.validation_data.part_list(self.element)
} }

View file

@ -806,7 +806,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
return; return;
} }
let is_html_select_element = element.map_or(false, |e| { let is_html_select_element = element.map_or(false, |e| {
e.is_html_element() && e.local_name() == &*local_name!("select") e.is_html_element() && e.local_name() == &*atom!("select")
}); });
if !is_html_select_element { if !is_html_select_element {
return; return;

View file

@ -1651,7 +1651,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
// //
// NOTE(emilio): See the comment regarding on when this may // NOTE(emilio): See the comment regarding on when this may
// break in visit_complex_selector. // break in visit_complex_selector.
self.mapped_ids.insert(id.clone()); self.mapped_ids.insert(id.0.clone());
}, },
_ => {}, _ => {},
} }
@ -2078,7 +2078,7 @@ impl CascadeData {
self.part_rules self.part_rules
.get_or_insert_with(|| Box::new(Default::default())) .get_or_insert_with(|| Box::new(Default::default()))
.for_insertion(pseudo_element) .for_insertion(pseudo_element)
.try_entry(parts.last().unwrap().clone())? .try_entry(parts.last().unwrap().clone().0)?
.or_insert_with(SmallVec::new) .or_insert_with(SmallVec::new)
.try_push(rule)?; .try_push(rule)?;
} else { } else {

View file

@ -13,6 +13,7 @@ use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
use crate::Atom; use crate::Atom;
pub use cssparser::{serialize_identifier, serialize_name, CowRcStr, Parser}; pub use cssparser::{serialize_identifier, serialize_name, CowRcStr, Parser};
pub use cssparser::{SourceLocation, Token, RGBA}; pub use cssparser::{SourceLocation, Token, RGBA};
use precomputed_hash::PrecomputedHash;
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Debug, Write}; use std::fmt::{self, Debug, Write};
use std::hash; use std::hash;
@ -84,6 +85,112 @@ where
serialize_name(&ident, dest) serialize_name(&ident, dest)
} }
/// A CSS string stored as an `Atom`.
#[repr(transparent)]
#[derive(
Clone,
Debug,
Default,
Deref,
Eq,
Hash,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
pub struct AtomString(pub Atom);
impl cssparser::ToCss for AtomString {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: Write,
{
self.0
.with_str(|s| cssparser::CssStringWriter::new(dest).write_str(s))
}
}
impl PrecomputedHash for AtomString {
#[inline]
fn precomputed_hash(&self) -> u32 {
self.0.precomputed_hash()
}
}
impl<'a> From<&'a str> for AtomString {
#[inline]
fn from(string: &str) -> Self {
Self(Atom::from(string))
}
}
/// A CSS `<ident>` stored as an `Atom`.
#[repr(transparent)]
#[derive(
Clone,
Debug,
Default,
Deref,
Eq,
Hash,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
pub struct AtomIdent(pub Atom);
impl cssparser::ToCss for AtomIdent {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: Write,
{
serialize_atom_identifier(&self.0, dest)
}
}
impl PrecomputedHash for AtomIdent {
#[inline]
fn precomputed_hash(&self) -> u32 {
self.0.precomputed_hash()
}
}
impl<'a> From<&'a str> for AtomIdent {
#[inline]
fn from(string: &str) -> Self {
Self(Atom::from(string))
}
}
impl AtomIdent {
/// Like `Atom::with` but for `AtomIdent`.
#[cfg(feature = "gecko")]
pub unsafe fn with<F, R>(ptr: *const crate::gecko_bindings::structs::nsAtom, callback: F) -> R
where
F: FnOnce(&Self) -> R,
{
Atom::with(ptr, |atom: &Atom| {
// safety: repr(transparent)
let atom = atom as *const Atom as *const AtomIdent;
callback(&*atom)
})
}
}
#[cfg(feature = "gecko")]
impl std::borrow::Borrow<crate::gecko_string_cache::WeakAtom> for AtomIdent {
#[inline]
fn borrow(&self) -> &crate::gecko_string_cache::WeakAtom {
self.0.borrow()
}
}
/// Serialize a normalized value into percentage. /// Serialize a normalized value into percentage.
pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
where where