aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/selectors/builder.rs2
-rw-r--r--components/selectors/matching.rs20
-rw-r--r--components/selectors/parser.rs44
-rw-r--r--components/style/dom.rs8
-rw-r--r--components/style/invalidation/element/invalidation_map.rs19
-rw-r--r--components/style/invalidation/element/invalidator.rs30
-rw-r--r--components/style/selector_map.rs1
-rw-r--r--components/style/stylist.rs5
8 files changed, 82 insertions, 47 deletions
diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs
index b81c729eea5..d4ed2d309b6 100644
--- a/components/selectors/builder.rs
+++ b/components/selectors/builder.rs
@@ -314,7 +314,7 @@ fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>)
Component::FirstChild | Component::LastChild |
Component::OnlyChild | Component::Root |
Component::Empty | Component::Scope |
- Component::Host |
+ Component::Host(..) |
Component::NthChild(..) |
Component::NthLastChild(..) |
Component::NthOfType(..) |
diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs
index 527d1224e6b..5e78e50d544 100644
--- a/components/selectors/matching.rs
+++ b/components/selectors/matching.rs
@@ -692,10 +692,10 @@ where
match *selector {
Component::Combinator(_) => unreachable!(),
Component::Slotted(ref selector) => {
+ // <slots> are never flattened tree slottables.
+ !element.is_html_slot_element() &&
+ element.assigned_slot().is_some() &&
context.shared.nest(|context| {
- // <slots> are never flattened tree slottables.
- !element.is_html_slot_element() &&
- element.assigned_slot().is_some() &&
matches_complex_selector(
selector.iter(),
element,
@@ -814,8 +814,18 @@ where
flags_setter(element, ElementSelectorFlags::HAS_EMPTY_SELECTOR);
element.is_empty()
}
- Component::Host => {
- context.shared.shadow_host().map_or(false, |host| host == element.opaque())
+ Component::Host(ref selector) => {
+ context.shared.shadow_host().map_or(false, |host| host == element.opaque()) &&
+ selector.as_ref().map_or(true, |selector| {
+ context.shared.nest(|context| {
+ matches_complex_selector(
+ selector.iter(),
+ element,
+ context,
+ flags_setter,
+ )
+ })
+ })
}
Component::Scope => {
match context.shared.scope_element {
diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs
index dfcae65a9cc..9fbd711ab78 100644
--- a/components/selectors/parser.rs
+++ b/components/selectors/parser.rs
@@ -381,11 +381,14 @@ where
}
match *self {
- Slotted(ref selectors) => {
- for selector in selectors.iter() {
- if !selector.visit(visitor) {
- return false;
- }
+ Slotted(ref selector) => {
+ if !selector.visit(visitor) {
+ return false;
+ }
+ }
+ Host(Some(ref selector)) => {
+ if !selector.visit(visitor) {
+ return false;
}
}
Negation(ref negated) => {
@@ -618,7 +621,7 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
/// combinators to the left.
#[inline]
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
- self.all(|component| matches!(*component, Component::Host)) &&
+ self.all(|component| matches!(*component, Component::Host(..))) &&
self.next_sequence().is_none()
}
@@ -793,10 +796,6 @@ pub enum Component<Impl: SelectorImpl> {
Root,
Empty,
Scope,
- /// The `:host` pseudo-class:
- ///
- /// https://drafts.csswg.org/css-scoping/#host-selector
- Host,
NthChild(i32, i32),
NthLastChild(i32, i32),
NthOfType(i32, i32),
@@ -815,7 +814,19 @@ pub enum Component<Impl: SelectorImpl> {
/// NOTE(emilio): This should support a list of selectors, but as of this
/// writing no other browser does, and that allows them to put ::slotted()
/// in the rule hash, so we do that too.
+ ///
+ /// See https://github.com/w3c/csswg-drafts/issues/2158
Slotted(Selector<Impl>),
+ /// The `:host` pseudo-class:
+ ///
+ /// https://drafts.csswg.org/css-scoping/#host-selector
+ ///
+ /// NOTE(emilio): This should support a list of selectors, but as of this
+ /// writing no other browser does, and that allows them to put :host()
+ /// in the rule hash, so we do that too.
+ ///
+ /// See https://github.com/w3c/csswg-drafts/issues/2158
+ Host(Option<Selector<Impl>>),
PseudoElement(Impl::PseudoElement),
}
@@ -1119,7 +1130,15 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
Root => dest.write_str(":root"),
Empty => dest.write_str(":empty"),
Scope => dest.write_str(":scope"),
- Host => dest.write_str(":host"),
+ Host(ref selector) => {
+ dest.write_str(":host")?;
+ if let Some(ref selector) = *selector {
+ dest.write_char('(')?;
+ selector.to_css(dest)?;
+ dest.write_char(')')?;
+ }
+ Ok(())
+ },
FirstOfType => dest.write_str(":first-of-type"),
LastOfType => dest.write_str(":last-of-type"),
OnlyOfType => dest.write_str(":only-of-type"),
@@ -1816,6 +1835,7 @@ where
"nth-of-type" => return Ok(parse_nth_pseudo_class(input, Component::NthOfType)?),
"nth-last-child" => return Ok(parse_nth_pseudo_class(input, Component::NthLastChild)?),
"nth-last-of-type" => return Ok(parse_nth_pseudo_class(input, Component::NthLastOfType)?),
+ "host" => return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input)?))),
"not" => {
if inside_negation {
return Err(input.new_custom_error(
@@ -1969,7 +1989,7 @@ where
"root" => Ok(Component::Root),
"empty" => Ok(Component::Empty),
"scope" => Ok(Component::Scope),
- "host" if P::parse_host(parser) => Ok(Component::Host),
+ "host" if P::parse_host(parser) => Ok(Component::Host(None)),
"first-of-type" => Ok(Component::FirstOfType),
"last-of-type" => Ok(Component::LastOfType),
"only-of-type" => Ok(Component::OnlyOfType),
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 7e63fd8ba50..0c9bcbe3c4d 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -794,6 +794,14 @@ pub trait TElement
);
}
+ if let Some(shadow) = self.shadow_root() {
+ f(
+ shadow.style_data(),
+ self.as_node().owner_doc().quirks_mode(),
+ Some(shadow.host()),
+ );
+ }
+
let mut current = self.assigned_slot();
while let Some(slot) = current {
// Slots can only have assigned nodes when in a shadow tree.
diff --git a/components/style/invalidation/element/invalidation_map.rs b/components/style/invalidation/element/invalidation_map.rs
index 05c67bcc383..0a2edd4aec9 100644
--- a/components/style/invalidation/element/invalidation_map.rs
+++ b/components/style/invalidation/element/invalidation_map.rs
@@ -207,16 +207,6 @@ impl InvalidationMap {
})
}
- /// Adds a selector to this `InvalidationMap`. Returns Err(..) to
- /// signify OOM.
- pub fn note_selector(
- &mut self,
- selector: &Selector<SelectorImpl>,
- quirks_mode: QuirksMode,
- ) -> Result<(), FailedAllocationError> {
- self.collect_invalidations_for(selector, quirks_mode)
- }
-
/// Clears this map, leaving it empty.
pub fn clear(&mut self) {
self.class_to_selector.clear();
@@ -228,13 +218,14 @@ impl InvalidationMap {
self.has_class_attribute_selectors = false;
}
- // Returns Err(..) to signify OOM.
- fn collect_invalidations_for(
+ /// Adds a selector to this `InvalidationMap`. Returns Err(..) to
+ /// signify OOM.
+ pub fn note_selector(
&mut self,
selector: &Selector<SelectorImpl>,
- quirks_mode: QuirksMode
+ quirks_mode: QuirksMode,
) -> Result<(), FailedAllocationError> {
- debug!("InvalidationMap::collect_invalidations_for({:?})", selector);
+ debug!("InvalidationMap::note_selector({:?})", selector);
let mut iter = selector.iter();
let mut combinator;
diff --git a/components/style/invalidation/element/invalidator.rs b/components/style/invalidation/element/invalidator.rs
index 77e9f875bdd..3392c58e356 100644
--- a/components/style/invalidation/element/invalidator.rs
+++ b/components/style/invalidation/element/invalidator.rs
@@ -6,7 +6,7 @@
//! element styles need to be invalidated.
use context::StackLimitChecker;
-use dom::{TElement, TNode};
+use dom::{TElement, TNode, TShadowRoot};
use selector_parser::SelectorImpl;
use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext};
use selectors::matching::matches_compound_selector_from;
@@ -534,20 +534,22 @@ where
let mut any_descendant = false;
- // NOTE(emilio): This should not be needed for Shadow DOM for normal
- // element state / attribute invalidations (it's needed for XBL though,
- // due to the weird way the anon content there works (it doesn't block
- // combinators)).
+ // NOTE(emilio): This is only needed for Shadow DOM to invalidate
+ // correctly on :host(..) changes. Instead of doing this, we could add
+ // a third kind of invalidation list that walks shadow root children,
+ // but it's not clear it's worth it.
//
- // However, it's needed as of right now for document state invalidation,
- // were we rely on iterating every element that ends up in the composed
- // doc.
- //
- // Also, we could avoid having that special-case for document state
- // invalidations if we invalidate for document state changes per
- // subtree, though that's kind of annoying because we need to invalidate
- // the shadow host subtree (to handle :host and ::slotted), and the
- // actual shadow tree (to handle all other rules in the ShadowRoot).
+ // Also, it's needed as of right now for document state invalidation,
+ // where we rely on iterating every element that ends up in the composed
+ // doc, but we could fix that invalidating per subtree.
+ if let Some(root) = self.element.shadow_root() {
+ any_descendant |=
+ self.invalidate_dom_descendants_of(root.as_node(), invalidations);
+ }
+
+ // This is needed for XBL (technically) unconditionally, because XBL
+ // bindings do not block combinators in any way. However this is kinda
+ // broken anyway, since we should be looking at XBL rules too.
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations);
diff --git a/components/style/selector_map.rs b/components/style/selector_map.rs
index c1f02b5797f..03979549709 100644
--- a/components/style/selector_map.rs
+++ b/components/style/selector_map.rs
@@ -457,6 +457,7 @@ fn specific_bucket_for<'a>(
//
// Meanwhile taking the code path below is slower, but still correct.
// Component::Slotted(ref selector) => find_bucket(selector.iter()),
+ Component::Host(Some(ref selector)) => find_bucket(selector.iter()),
_ => Bucket::Universal
}
}
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index 686ce6a6b6e..6a8ea544c39 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -2238,7 +2238,10 @@ impl CascadeData {
);
if rebuild_kind.should_rebuild_invalidation() {
- self.invalidation_map.note_selector(&rule.selector, quirks_mode)?;
+ self.invalidation_map.note_selector(
+ selector,
+ quirks_mode,
+ )?;
let mut visitor = StylistSelectorVisitor {
needs_revalidation: false,
passed_rightmost_selector: false,