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

@ -11,7 +11,7 @@ use crate::invalidation::element::document_state::InvalidationMatchingData;
use crate::selector_parser::{Direction, SelectorParser};
use crate::str::starts_with_ignore_ascii_case;
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::{CowRcStr, SourceLocation, ToCss, Token};
use selectors::parser::{SelectorParseErrorKind, ParseErrorRecovery};
@ -39,7 +39,7 @@ bitflags! {
}
/// 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 {
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => {
@ -77,7 +77,7 @@ impl ToCss for NonTSPseudoClass {
$(NonTSPseudoClass::$name => concat!(":", $css),)*
NonTSPseudoClass::Lang(ref s) => {
dest.write_str(":lang(")?;
serialize_atom_identifier(s, dest)?;
s.to_css(dest)?;
return dest.write_char(')');
},
NonTSPseudoClass::MozLocaleDir(ref dir) => {
@ -270,12 +270,10 @@ pub struct SelectorImpl;
impl ::selectors::SelectorImpl for SelectorImpl {
type ExtraMatchingData = InvalidationMatchingData;
type AttrValue = Atom;
type Identifier = Atom;
type ClassName = Atom;
type PartName = Atom;
type LocalName = Atom;
type NamespacePrefix = Atom;
type AttrValue = AtomString;
type Identifier = AtomIdent;
type LocalName = AtomIdent;
type NamespacePrefix = AtomIdent;
type NamespaceUrl = Namespace;
type BorrowedNamespaceUrl = WeakNamespace;
type BorrowedLocalName = WeakAtom;
@ -386,7 +384,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
let pseudo_class = match_ignore_ascii_case! { &name,
"lang" => {
let name = parser.expect_ident_or_string()?;
NonTSPseudoClass::Lang(Atom::from(name.as_ref()))
NonTSPseudoClass::Lang(Lang::from(name.as_ref()))
},
"-moz-locale-dir" => {
NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?)
@ -475,7 +473,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
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()
}
}

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::ServoElementSnapshotTable;
use crate::invalidation::element::element_wrapper::ElementSnapshot;
use crate::selector_parser::AttrValue;
use crate::string_cache::{Atom, Namespace};
use crate::values::{AtomIdent, AtomString};
use crate::LocalName;
use crate::WeakAtom;
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator};
use selectors::attr::{CaseSensitivity, NamespaceConstraint};
@ -74,10 +77,10 @@ impl GeckoElementSnapshot {
#[inline]
pub fn each_attr_changed<F>(&self, mut callback: F)
where
F: FnMut(&Atom),
F: FnMut(&AtomIdent),
{
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(
&self,
ns: &NamespaceConstraint<&Namespace>,
local_name: &Atom,
operation: &AttrSelectorOperation<&Atom>,
local_name: &LocalName,
operation: &AttrSelectorOperation<&AttrValue>,
) -> bool {
unsafe {
match *operation {
@ -188,7 +191,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
#[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")) {
Some(attr) => attr,
None => return false,
@ -198,12 +201,12 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
#[inline]
fn imported_part(&self, name: &Atom) -> Option<Atom> {
fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
snapshot_helpers::imported_part(&*self.mAttrs, name)
}
#[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) {
return false;
}
@ -214,7 +217,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
#[inline]
fn each_class<F>(&self, callback: F)
where
F: FnMut(&Atom),
F: FnMut(&AtomIdent),
{
if !self.has_any(Flags::MaybeClass) {
return;
@ -224,12 +227,12 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
#[inline]
fn lang_attr(&self) -> Option<Atom> {
fn lang_attr(&self) -> Option<AtomString> {
let ptr = unsafe { bindings::Gecko_SnapshotLangValue(self) };
if ptr.is_null() {
None
} 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::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 selectors::attr::CaseSensitivity;
@ -85,8 +87,8 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> {
#[inline(always)]
pub(super) fn each_exported_part(
attrs: &[structs::AttrArray_InternalAttr],
name: &Atom,
mut callback: impl FnMut(&Atom),
name: &AtomIdent,
mut callback: impl FnMut(&AtomIdent),
) {
let attr = match find_attr(attrs, &atom!("exportparts")) {
Some(attr) => attr,
@ -100,7 +102,7 @@ pub(super) fn each_exported_part(
unsafe {
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)]
pub(super) fn imported_part(
attrs: &[structs::AttrArray_InternalAttr],
name: &Atom,
) -> Option<Atom> {
name: &AtomIdent,
) -> Option<AtomIdent> {
let attr = find_attr(attrs, &atom!("exportparts"))?;
let atom = unsafe { bindings::Gecko_Element_ImportedPart(attr, name.as_ptr()) };
if atom.is_null() {
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,
/// returns whether the attribute has that name.
#[inline(always)]
pub fn has_class_or_part(
name: &Atom,
name: &AtomIdent,
case_sensitivity: CaseSensitivity,
attr: &structs::nsAttrValue,
) -> bool {
@ -147,15 +149,15 @@ pub fn has_class_or_part(
#[inline(always)]
pub fn each_class_or_part<F>(attr: &structs::nsAttrValue, mut callback: F)
where
F: FnMut(&Atom),
F: FnMut(&AtomIdent),
{
unsafe {
match get_class_or_part_from_attr(attr) {
Class::None => {},
Class::One(atom) => Atom::with(atom, callback),
Class::One(atom) => AtomIdent::with(atom, callback),
Class::More(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::Length;
use crate::values::specified::length::FontBaseSize;
use crate::values::{AtomIdent, AtomString};
use crate::CaseSensitivityExt;
use crate::LocalName;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator};
use selectors::attr::{CaseSensitivity, NamespaceConstraint};
@ -130,7 +132,7 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
}
#[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
Self: 'a,
{
@ -186,7 +188,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
}
#[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
Self: 'a,
{
@ -801,7 +803,7 @@ impl<'le> GeckoElement<'le> {
return false;
}
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>> {
@ -1270,7 +1272,7 @@ impl<'le> TElement for GeckoElement<'le> {
}
#[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()) }
}
@ -1297,7 +1299,7 @@ impl<'le> TElement for GeckoElement<'le> {
fn each_class<F>(&self, callback: F)
where
F: FnMut(&Atom),
F: FnMut(&AtomIdent),
{
let attr = match self.get_class_attr() {
Some(c) => c,
@ -1308,16 +1310,16 @@ impl<'le> TElement for GeckoElement<'le> {
}
#[inline]
fn each_exported_part<F>(&self, name: &Atom, callback: F)
fn each_exported_part<F>(&self, name: &AtomIdent, callback: F)
where
F: FnMut(&Atom),
F: FnMut(&AtomIdent),
{
snapshot_helpers::each_exported_part(self.attrs(), name, callback)
}
fn each_part<F>(&self, callback: F)
where
F: FnMut(&Atom),
F: FnMut(&AtomIdent),
{
let attr = match self.get_part_attr() {
Some(c) => c,
@ -1615,7 +1617,7 @@ impl<'le> TElement for GeckoElement<'le> {
if ptr.is_null() {
None
} 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
// single language tag, and which performs simple dash-prefix matching
// on it.
let override_lang_ptr = match &override_lang {
&Some(Some(ref atom)) => atom.as_ptr(),
let override_lang_ptr = match override_lang {
Some(Some(ref atom)) => atom.as_ptr(),
_ => ptr::null_mut(),
};
unsafe {
@ -1638,7 +1640,7 @@ impl<'le> TElement for GeckoElement<'le> {
}
fn is_html_document_body_element(&self) -> bool {
if self.local_name() != &*local_name!("body") {
if self.local_name() != &**local_name!("body") {
return false;
}
@ -1895,8 +1897,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
fn attr_matches(
&self,
ns: &NamespaceConstraint<&Namespace>,
local_name: &Atom,
operation: &AttrSelectorOperation<&Atom>,
local_name: &LocalName,
operation: &AttrSelectorOperation<&AttrValue>,
) -> bool {
unsafe {
match *operation {
@ -2180,7 +2182,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
#[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() {
return false;
}
@ -2194,7 +2196,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
#[inline]
fn is_part(&self, name: &Atom) -> bool {
fn is_part(&self, name: &AtomIdent) -> bool {
let attr = match self.get_part_attr() {
Some(c) => c,
None => return false,
@ -2204,12 +2206,12 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
#[inline]
fn imported_part(&self, name: &Atom) -> Option<Atom> {
fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
snapshot_helpers::imported_part(self.attrs(), name)
}
#[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() {
Some(c) => c,
None => return false,