mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
style: Add parsing support for ::part().
Disabled for now of course. This should be pretty uncontroversial I'd think. Differential Revision: https://phabricator.services.mozilla.com/D28060
This commit is contained in:
parent
9f73576f6a
commit
a23ad3be50
10 changed files with 106 additions and 17 deletions
|
@ -747,6 +747,7 @@ where
|
||||||
Component::ExplicitUniversalType |
|
Component::ExplicitUniversalType |
|
||||||
Component::LocalName(..) |
|
Component::LocalName(..) |
|
||||||
Component::ID(..) |
|
Component::ID(..) |
|
||||||
|
Component::Part(..) |
|
||||||
Component::Class(..) |
|
Component::Class(..) |
|
||||||
Component::AttributeInNoNamespaceExists { .. } |
|
Component::AttributeInNoNamespaceExists { .. } |
|
||||||
Component::AttributeInNoNamespace { .. } |
|
Component::AttributeInNoNamespace { .. } |
|
||||||
|
|
|
@ -270,6 +270,7 @@ where
|
||||||
Component::Combinator(..) => {
|
Component::Combinator(..) => {
|
||||||
unreachable!("Found combinator in simple selectors vector?");
|
unreachable!("Found combinator in simple selectors vector?");
|
||||||
},
|
},
|
||||||
|
Component::Part(..) |
|
||||||
Component::PseudoElement(..) | Component::LocalName(..) => {
|
Component::PseudoElement(..) | Component::LocalName(..) => {
|
||||||
specificity.element_selectors += 1
|
specificity.element_selectors += 1
|
||||||
},
|
},
|
||||||
|
|
|
@ -450,6 +450,7 @@ where
|
||||||
|
|
||||||
element.containing_shadow_host()
|
element.containing_shadow_host()
|
||||||
},
|
},
|
||||||
|
Combinator::Part => element.containing_shadow_host(),
|
||||||
Combinator::SlotAssignment => {
|
Combinator::SlotAssignment => {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
context.current_host.is_some(),
|
context.current_host.is_some(),
|
||||||
|
@ -517,6 +518,7 @@ where
|
||||||
Combinator::Child |
|
Combinator::Child |
|
||||||
Combinator::Descendant |
|
Combinator::Descendant |
|
||||||
Combinator::SlotAssignment |
|
Combinator::SlotAssignment |
|
||||||
|
Combinator::Part |
|
||||||
Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
|
Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -671,6 +673,7 @@ where
|
||||||
|
|
||||||
match *selector {
|
match *selector {
|
||||||
Component::Combinator(_) => unreachable!(),
|
Component::Combinator(_) => unreachable!(),
|
||||||
|
Component::Part(ref part) => element.is_part(part),
|
||||||
Component::Slotted(ref selector) => {
|
Component::Slotted(ref selector) => {
|
||||||
// <slots> are never flattened tree slottables.
|
// <slots> are never flattened tree slottables.
|
||||||
!element.is_html_slot_element() &&
|
!element.is_html_slot_element() &&
|
||||||
|
|
|
@ -68,24 +68,30 @@ bitflags! {
|
||||||
/// Whether we're inside a negation. If we're inside a negation, we're
|
/// Whether we're inside a negation. If we're inside a negation, we're
|
||||||
/// not allowed to add another negation or such, for example.
|
/// not allowed to add another negation or such, for example.
|
||||||
const INSIDE_NEGATION = 1 << 0;
|
const INSIDE_NEGATION = 1 << 0;
|
||||||
/// Whether we've parsed an ::slotted() pseudo-element already.
|
/// Whether we've parsed a ::slotted() pseudo-element already.
|
||||||
///
|
///
|
||||||
/// If so, then we can only parse a subset of pseudo-elements, and
|
/// If so, then we can only parse a subset of pseudo-elements, and
|
||||||
/// whatever comes after them if so.
|
/// whatever comes after them if so.
|
||||||
const AFTER_SLOTTED = 1 << 1;
|
const AFTER_SLOTTED = 1 << 1;
|
||||||
|
/// Whether we've parsed a ::part() pseudo-element already.
|
||||||
|
///
|
||||||
|
/// If so, then we can only parse a subset of pseudo-elements, and
|
||||||
|
/// whatever comes after them if so.
|
||||||
|
const AFTER_PART = 1 << 2;
|
||||||
/// Whether we've parsed a pseudo-element (as in, an
|
/// Whether we've parsed a pseudo-element (as in, an
|
||||||
/// `Impl::PseudoElement` thus not accounting for `::slotted`) already.
|
/// `Impl::PseudoElement` thus not accounting for `::slotted` or
|
||||||
|
/// `::part`) already.
|
||||||
///
|
///
|
||||||
/// If so, then other pseudo-elements and most other selectors are
|
/// If so, then other pseudo-elements and most other selectors are
|
||||||
/// disallowed.
|
/// disallowed.
|
||||||
const AFTER_PSEUDO_ELEMENT = 1 << 2;
|
const AFTER_PSEUDO_ELEMENT = 1 << 3;
|
||||||
/// Whether we've parsed a non-stateful pseudo-element (again, as-in
|
/// Whether we've parsed a non-stateful pseudo-element (again, as-in
|
||||||
/// `Impl::PseudoElement`) already. If so, then other pseudo-classes are
|
/// `Impl::PseudoElement`) already. If so, then other pseudo-classes are
|
||||||
/// disallowed. If this flag is set, `AFTER_PSEUDO_ELEMENT` must be set
|
/// disallowed. If this flag is set, `AFTER_PSEUDO_ELEMENT` must be set
|
||||||
/// as well.
|
/// as well.
|
||||||
const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 3;
|
const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
|
||||||
/// Whether we are after any of the pseudo-like things.
|
/// Whether we are after any of the pseudo-like things.
|
||||||
const AFTER_PSEUDO = Self::AFTER_SLOTTED.bits | Self::AFTER_PSEUDO_ELEMENT.bits;
|
const AFTER_PSEUDO = Self::AFTER_PART.bits | Self::AFTER_SLOTTED.bits | Self::AFTER_PSEUDO_ELEMENT.bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +106,14 @@ impl SelectorParsingState {
|
||||||
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
|
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(emilio): Should we allow other ::part()s after ::part()?
|
||||||
|
//
|
||||||
|
// See https://github.com/w3c/csswg-drafts/issues/3841
|
||||||
|
#[inline]
|
||||||
|
fn allows_part(self) -> bool {
|
||||||
|
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn allows_non_functional_pseudo_classes(self) -> bool {
|
fn allows_non_functional_pseudo_classes(self) -> bool {
|
||||||
!self.intersects(SelectorParsingState::AFTER_SLOTTED | SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT)
|
!self.intersects(SelectorParsingState::AFTER_SLOTTED | SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT)
|
||||||
|
@ -156,6 +170,7 @@ macro_rules! with_all_bounds {
|
||||||
type AttrValue: $($InSelector)*;
|
type AttrValue: $($InSelector)*;
|
||||||
type Identifier: $($InSelector)*;
|
type Identifier: $($InSelector)*;
|
||||||
type ClassName: $($InSelector)*;
|
type ClassName: $($InSelector)*;
|
||||||
|
type PartName: $($InSelector)*;
|
||||||
type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
|
type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
|
||||||
type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
|
type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
|
||||||
type NamespacePrefix: $($InSelector)* + Default;
|
type NamespacePrefix: $($InSelector)* + Default;
|
||||||
|
@ -196,6 +211,11 @@ pub trait Parser<'i> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether to parse the `::part()` pseudo-element.
|
||||||
|
fn parse_part(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether to parse the `:host` pseudo-class.
|
/// Whether to parse the `:host` pseudo-class.
|
||||||
fn parse_host(&self) -> bool {
|
fn parse_host(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
@ -841,6 +861,9 @@ pub enum Combinator {
|
||||||
/// Another combinator used for ::slotted(), which represent the jump from
|
/// Another combinator used for ::slotted(), which represent the jump from
|
||||||
/// a node to its assigned slot.
|
/// a node to its assigned slot.
|
||||||
SlotAssignment,
|
SlotAssignment,
|
||||||
|
/// Another combinator used for `::part()`, which represents the jump from
|
||||||
|
/// the part to the containing shadow host.
|
||||||
|
Part,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Combinator {
|
impl Combinator {
|
||||||
|
@ -934,8 +957,7 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
LastOfType,
|
LastOfType,
|
||||||
OnlyOfType,
|
OnlyOfType,
|
||||||
NonTSPseudoClass(#[shmem(field_bound)] Impl::NonTSPseudoClass),
|
NonTSPseudoClass(#[shmem(field_bound)] Impl::NonTSPseudoClass),
|
||||||
/// The ::slotted() pseudo-element (which isn't actually a pseudo-element,
|
/// The ::slotted() pseudo-element:
|
||||||
/// and probably should be a pseudo-class):
|
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-scoping/#slotted-pseudo
|
/// https://drafts.csswg.org/css-scoping/#slotted-pseudo
|
||||||
///
|
///
|
||||||
|
@ -947,6 +969,9 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
///
|
///
|
||||||
/// See https://github.com/w3c/csswg-drafts/issues/2158
|
/// See https://github.com/w3c/csswg-drafts/issues/2158
|
||||||
Slotted(Selector<Impl>),
|
Slotted(Selector<Impl>),
|
||||||
|
/// The `::part` pseudo-element.
|
||||||
|
/// https://drafts.csswg.org/css-shadow-parts/#part
|
||||||
|
Part(#[shmem(field_bound)] Impl::PartName),
|
||||||
/// The `:host` pseudo-class:
|
/// The `:host` pseudo-class:
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-scoping/#host-selector
|
/// https://drafts.csswg.org/css-scoping/#host-selector
|
||||||
|
@ -1196,7 +1221,8 @@ impl ToCss for Combinator {
|
||||||
Combinator::Descendant => dest.write_str(" "),
|
Combinator::Descendant => dest.write_str(" "),
|
||||||
Combinator::NextSibling => dest.write_str(" + "),
|
Combinator::NextSibling => dest.write_str(" + "),
|
||||||
Combinator::LaterSibling => dest.write_str(" ~ "),
|
Combinator::LaterSibling => dest.write_str(" ~ "),
|
||||||
Combinator::PseudoElement => Ok(()),
|
Combinator::PseudoElement |
|
||||||
|
Combinator::Part |
|
||||||
Combinator::SlotAssignment => Ok(()),
|
Combinator::SlotAssignment => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1236,6 +1262,11 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
|
||||||
selector.to_css(dest)?;
|
selector.to_css(dest)?;
|
||||||
dest.write_char(')')
|
dest.write_char(')')
|
||||||
},
|
},
|
||||||
|
Part(ref part_name) => {
|
||||||
|
dest.write_str("::part(")?;
|
||||||
|
display_to_css_identifier(part_name, dest)?;
|
||||||
|
dest.write_char(')')
|
||||||
|
},
|
||||||
PseudoElement(ref p) => p.to_css(dest),
|
PseudoElement(ref p) => p.to_css(dest),
|
||||||
ID(ref s) => {
|
ID(ref s) => {
|
||||||
dest.write_char('#')?;
|
dest.write_char('#')?;
|
||||||
|
@ -1407,15 +1438,12 @@ where
|
||||||
{
|
{
|
||||||
let mut builder = SelectorBuilder::default();
|
let mut builder = SelectorBuilder::default();
|
||||||
|
|
||||||
let mut has_pseudo_element;
|
let mut has_pseudo_element = false;
|
||||||
let mut slotted;
|
let mut slotted = false;
|
||||||
'outer_loop: loop {
|
'outer_loop: loop {
|
||||||
// Parse a sequence of simple selectors.
|
// Parse a sequence of simple selectors.
|
||||||
match parse_compound_selector(parser, input, &mut builder)? {
|
let state = match parse_compound_selector(parser, input, &mut builder)? {
|
||||||
Some(state) => {
|
Some(state) => state,
|
||||||
has_pseudo_element = state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
|
|
||||||
slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
return Err(input.new_custom_error(if builder.has_combinators() {
|
return Err(input.new_custom_error(if builder.has_combinators() {
|
||||||
SelectorParseErrorKind::DanglingCombinator
|
SelectorParseErrorKind::DanglingCombinator
|
||||||
|
@ -1425,7 +1453,11 @@ where
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if has_pseudo_element || slotted {
|
if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
|
||||||
|
has_pseudo_element = state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
|
||||||
|
slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
|
||||||
|
let part = state.intersects(SelectorParsingState::AFTER_PART);
|
||||||
|
debug_assert!(has_pseudo_element || slotted || part);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1463,6 +1495,8 @@ where
|
||||||
builder.push_combinator(combinator);
|
builder.push_combinator(combinator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(emilio): We'll have to flag part() somehow as well, but we need more
|
||||||
|
// bits!
|
||||||
Ok(Selector(builder.build(has_pseudo_element, slotted)))
|
Ok(Selector(builder.build(has_pseudo_element, slotted)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1553,6 +1587,7 @@ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
|
||||||
SimpleSelector(Component<Impl>),
|
SimpleSelector(Component<Impl>),
|
||||||
PseudoElement(Impl::PseudoElement),
|
PseudoElement(Impl::PseudoElement),
|
||||||
SlottedPseudo(Selector<Impl>),
|
SlottedPseudo(Selector<Impl>),
|
||||||
|
PartPseudo(Impl::PartName),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1899,6 +1934,7 @@ where
|
||||||
return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation));
|
return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation));
|
||||||
},
|
},
|
||||||
Some(SimpleSelectorParseResult::PseudoElement(_)) |
|
Some(SimpleSelectorParseResult::PseudoElement(_)) |
|
||||||
|
Some(SimpleSelectorParseResult::PartPseudo(_)) |
|
||||||
Some(SimpleSelectorParseResult::SlottedPseudo(_)) => {
|
Some(SimpleSelectorParseResult::SlottedPseudo(_)) => {
|
||||||
let e = SelectorParseErrorKind::NonSimpleSelectorInNegation;
|
let e = SelectorParseErrorKind::NonSimpleSelectorInNegation;
|
||||||
return Err(input.new_custom_error(e));
|
return Err(input.new_custom_error(e));
|
||||||
|
@ -1955,6 +1991,11 @@ where
|
||||||
SimpleSelectorParseResult::SimpleSelector(s) => {
|
SimpleSelectorParseResult::SimpleSelector(s) => {
|
||||||
builder.push_simple_selector(s);
|
builder.push_simple_selector(s);
|
||||||
},
|
},
|
||||||
|
SimpleSelectorParseResult::PartPseudo(part_name) => {
|
||||||
|
state.insert(SelectorParsingState::AFTER_PART);
|
||||||
|
builder.push_combinator(Combinator::Part);
|
||||||
|
builder.push_simple_selector(Component::Part(part_name));
|
||||||
|
},
|
||||||
SimpleSelectorParseResult::SlottedPseudo(selector) => {
|
SimpleSelectorParseResult::SlottedPseudo(selector) => {
|
||||||
state.insert(SelectorParsingState::AFTER_SLOTTED);
|
state.insert(SelectorParsingState::AFTER_SLOTTED);
|
||||||
if !builder.is_empty() {
|
if !builder.is_empty() {
|
||||||
|
@ -2115,6 +2156,15 @@ where
|
||||||
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
||||||
}
|
}
|
||||||
let pseudo_element = if is_functional {
|
let pseudo_element = if is_functional {
|
||||||
|
if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
|
||||||
|
if !state.allows_part() {
|
||||||
|
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
||||||
|
}
|
||||||
|
let name = input.parse_nested_block(|input| {
|
||||||
|
Ok(input.expect_ident()?.as_ref().into())
|
||||||
|
})?;
|
||||||
|
return Ok(Some(SimpleSelectorParseResult::PartPseudo(name)));
|
||||||
|
}
|
||||||
if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
|
if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
|
||||||
if !state.allows_slotted() {
|
if !state.allows_slotted() {
|
||||||
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
|
||||||
|
@ -2298,6 +2348,7 @@ pub mod tests {
|
||||||
type AttrValue = DummyAtom;
|
type AttrValue = DummyAtom;
|
||||||
type Identifier = DummyAtom;
|
type Identifier = DummyAtom;
|
||||||
type ClassName = DummyAtom;
|
type ClassName = DummyAtom;
|
||||||
|
type PartName = DummyAtom;
|
||||||
type LocalName = DummyAtom;
|
type LocalName = DummyAtom;
|
||||||
type NamespaceUrl = DummyAtom;
|
type NamespaceUrl = DummyAtom;
|
||||||
type NamespacePrefix = DummyAtom;
|
type NamespacePrefix = DummyAtom;
|
||||||
|
@ -2336,6 +2387,10 @@ pub mod tests {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_part(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_non_ts_pseudo_class(
|
fn parse_non_ts_pseudo_class(
|
||||||
&self,
|
&self,
|
||||||
location: SourceLocation,
|
location: SourceLocation,
|
||||||
|
@ -2910,6 +2965,14 @@ pub mod tests {
|
||||||
assert!(parse("::slotted(div).foo").is_err());
|
assert!(parse("::slotted(div).foo").is_err());
|
||||||
assert!(parse("::slotted(div + bar)").is_err());
|
assert!(parse("::slotted(div + bar)").is_err());
|
||||||
assert!(parse("::slotted(div) + foo").is_err());
|
assert!(parse("::slotted(div) + foo").is_err());
|
||||||
|
|
||||||
|
assert!(parse("::part()").is_err());
|
||||||
|
assert!(parse("::part(42)").is_err());
|
||||||
|
// Though note https://github.com/w3c/csswg-drafts/issues/3502
|
||||||
|
assert!(parse("::part(foo bar)").is_err());
|
||||||
|
assert!(parse("::part(foo):hover").is_ok());
|
||||||
|
assert!(parse("::part(foo) + bar").is_err());
|
||||||
|
|
||||||
assert!(parse("div ::slotted(div)").is_ok());
|
assert!(parse("div ::slotted(div)").is_ok());
|
||||||
assert!(parse("div + slot::slotted(div)").is_ok());
|
assert!(parse("div + slot::slotted(div)").is_ok());
|
||||||
assert!(parse("div + slot::slotted(div.foo)").is_ok());
|
assert!(parse("div + slot::slotted(div.foo)").is_ok());
|
||||||
|
|
|
@ -110,6 +110,11 @@ pub trait Element: Sized + Clone + Debug {
|
||||||
case_sensitivity: CaseSensitivity,
|
case_sensitivity: CaseSensitivity,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
|
fn is_part(
|
||||||
|
&self,
|
||||||
|
name: &<Self::Impl as SelectorImpl>::PartName,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
/// Returns whether this element matches `:empty`.
|
/// Returns whether this element matches `:empty`.
|
||||||
///
|
///
|
||||||
/// That is, whether it does not contain any child element or any non-zero-length text node.
|
/// That is, whether it does not contain any child element or any non-zero-length text node.
|
||||||
|
|
|
@ -289,6 +289,7 @@ impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
type AttrValue = Atom;
|
type AttrValue = Atom;
|
||||||
type Identifier = Atom;
|
type Identifier = Atom;
|
||||||
type ClassName = Atom;
|
type ClassName = Atom;
|
||||||
|
type PartName = Atom;
|
||||||
type LocalName = Atom;
|
type LocalName = Atom;
|
||||||
type NamespacePrefix = Atom;
|
type NamespacePrefix = Atom;
|
||||||
type NamespaceUrl = Namespace;
|
type NamespaceUrl = Namespace;
|
||||||
|
|
|
@ -2259,6 +2259,10 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
case_sensitivity.eq_atom(element_id, id)
|
case_sensitivity.eq_atom(element_id, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_part(&self, _name: &Atom) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
let attr = match self.get_class_attr() {
|
let attr = match self.get_class_attr() {
|
||||||
|
|
|
@ -340,6 +340,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_part(&self, _name: &Atom) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, 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),
|
||||||
|
|
|
@ -98,6 +98,7 @@ impl Dependency {
|
||||||
// an eager pseudo, and return only Descendants here if not.
|
// an eager pseudo, and return only Descendants here if not.
|
||||||
Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants,
|
Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants,
|
||||||
Some(Combinator::SlotAssignment) => DependencyInvalidationKind::SlottedElements,
|
Some(Combinator::SlotAssignment) => DependencyInvalidationKind::SlottedElements,
|
||||||
|
Some(Combinator::Part) => unimplemented!("Need to add invalidation for shadow parts"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,10 @@ impl<'a> Invalidation<'a> {
|
||||||
// We should be able to do better here!
|
// We should be able to do better here!
|
||||||
match self.selector.combinator_at_parse_order(self.offset - 1) {
|
match self.selector.combinator_at_parse_order(self.offset - 1) {
|
||||||
Combinator::Descendant | Combinator::LaterSibling | Combinator::PseudoElement => true,
|
Combinator::Descendant | Combinator::LaterSibling | Combinator::PseudoElement => true,
|
||||||
Combinator::SlotAssignment | Combinator::NextSibling | Combinator::Child => false,
|
Combinator::Part |
|
||||||
|
Combinator::SlotAssignment |
|
||||||
|
Combinator::NextSibling |
|
||||||
|
Combinator::Child => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +174,9 @@ impl<'a> Invalidation<'a> {
|
||||||
Combinator::Child | Combinator::Descendant | Combinator::PseudoElement => {
|
Combinator::Child | Combinator::Descendant | Combinator::PseudoElement => {
|
||||||
InvalidationKind::Descendant(DescendantInvalidationKind::Dom)
|
InvalidationKind::Descendant(DescendantInvalidationKind::Dom)
|
||||||
},
|
},
|
||||||
|
Combinator::Part => {
|
||||||
|
unimplemented!("Need to add invalidation for shadow parts");
|
||||||
|
},
|
||||||
Combinator::SlotAssignment => {
|
Combinator::SlotAssignment => {
|
||||||
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted)
|
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted)
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue