Skip to content

Commit

Permalink
Bug 1850974 - Make :is(:host) work. r=zrhoffman
Browse files Browse the repository at this point in the history
This should work per spec, see
w3c/csswg-drafts#9509.

Tweak a bit the selector flags set up so that checking for :host
selectors during CascadeData rebuilds is cheap.

Differential Revision: https://phabricator.services.mozilla.com/D191570
  • Loading branch information
emilio committed Oct 27, 2023
1 parent cbfbaec commit 722e4d2
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 103 deletions.
58 changes: 17 additions & 41 deletions selectors/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,12 @@ bitflags! {
const HAS_SLOTTED = 1 << 1;
const HAS_PART = 1 << 2;
const HAS_PARENT = 1 << 3;
const HAS_NON_FEATURELESS_COMPONENT = 1 << 4;
const HAS_HOST = 1 << 5;
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, ToShmem)]
pub struct SpecificityAndFlags {
/// There are two free bits here, since we use ten bits for each specificity
/// kind (id, class, element).
Expand All @@ -188,33 +190,6 @@ pub struct SpecificityAndFlags {
pub(crate) flags: SelectorFlags,
}

impl SpecificityAndFlags {
#[inline]
pub fn specificity(&self) -> u32 {
self.specificity
}

#[inline]
pub fn has_pseudo_element(&self) -> bool {
self.flags.intersects(SelectorFlags::HAS_PSEUDO)
}

#[inline]
pub fn has_parent_selector(&self) -> bool {
self.flags.intersects(SelectorFlags::HAS_PARENT)
}

#[inline]
pub fn is_slotted(&self) -> bool {
self.flags.intersects(SelectorFlags::HAS_SLOTTED)
}

#[inline]
pub fn is_part(&self) -> bool {
self.flags.intersects(SelectorFlags::HAS_PART)
}
}

const MAX_10BIT: u32 = (1u32 << 10) - 1;

#[derive(Add, AddAssign, Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
Expand Down Expand Up @@ -276,9 +251,12 @@ where
flags.insert(SelectorFlags::HAS_PSEUDO);
specificity.element_selectors += 1
},
Component::LocalName(..) => specificity.element_selectors += 1,
Component::LocalName(..) => {
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
specificity.element_selectors += 1
},
Component::Slotted(ref selector) => {
flags.insert(SelectorFlags::HAS_SLOTTED);
flags.insert(SelectorFlags::HAS_SLOTTED | SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
specificity.element_selectors += 1;
// Note that due to the way ::slotted works we only compete with
// other ::slotted rules, so the above rule doesn't really
Expand All @@ -287,21 +265,19 @@ where
//
// See: https://github.com/w3c/csswg-drafts/issues/1915
*specificity += Specificity::from(selector.specificity());
if selector.has_parent_selector() {
flags.insert(SelectorFlags::HAS_PARENT);
}
flags.insert(selector.flags());
},
Component::Host(ref selector) => {
flags.insert(SelectorFlags::HAS_HOST);
specificity.class_like_selectors += 1;
if let Some(ref selector) = *selector {
// See: https://github.com/w3c/csswg-drafts/issues/1915
*specificity += Specificity::from(selector.specificity());
if selector.has_parent_selector() {
flags.insert(SelectorFlags::HAS_PARENT);
}
flags.insert(selector.flags() - SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
}
},
Component::ID(..) => {
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
specificity.id_selectors += 1;
},
Component::Class(..) |
Expand All @@ -313,6 +289,7 @@ where
Component::Scope |
Component::Nth(..) |
Component::NonTSPseudoClass(..) => {
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
specificity.class_like_selectors += 1;
},
Component::NthOf(ref nth_of_data) => {
Expand All @@ -325,7 +302,7 @@ where
specificity.class_like_selectors += 1;
let sf = selector_list_specificity_and_flags(nth_of_data.selectors().iter());
*specificity += Specificity::from(sf.specificity);
flags.insert(sf.flags);
flags.insert(sf.flags | SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
},
// https://drafts.csswg.org/selectors/#specificity-rules:
//
Expand All @@ -344,7 +321,7 @@ where
Component::Has(ref relative_selectors) => {
let sf = relative_selector_list_specificity_and_flags(relative_selectors);
*specificity += Specificity::from(sf.specificity);
flags.insert(sf.flags);
flags.insert(sf.flags | SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
},
Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace |
Expand All @@ -354,6 +331,7 @@ where
Component::RelativeSelectorAnchor |
Component::Invalid(..) => {
// Does not affect specificity
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
},
}
}
Expand All @@ -377,9 +355,7 @@ pub(crate) fn selector_list_specificity_and_flags<'a, Impl: SelectorImpl>(
let mut flags = SelectorFlags::empty();
for selector in itr {
specificity = std::cmp::max(specificity, selector.specificity());
if selector.has_parent_selector() {
flags.insert(SelectorFlags::HAS_PARENT);
}
flags.insert(selector.flags());
}
SpecificityAndFlags { specificity, flags }
}
Expand Down

0 comments on commit 722e4d2

Please sign in to comment.