diff --git a/components/style/dom.rs b/components/style/dom.rs index fbe35e2e49d..adba4ff30db 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -807,6 +807,9 @@ pub trait TElement: /// data if it comes from Shadow DOM. /// /// Returns whether normal document author rules should apply. + /// + /// TODO(emilio): We could separate the invalidation data for elements + /// matching in other scopes to avoid over-invalidation. fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool where Self: 'a, @@ -841,11 +844,42 @@ pub trait TElement: // Slots can only have assigned nodes when in a shadow tree. let shadow = slot.containing_shadow().unwrap(); if let Some(data) = shadow.style_data() { - f(data, shadow.host()); + if data.any_slotted_rule() { + f(data, shadow.host()); + } } current = slot.assigned_slot(); } + if target.has_part_attr() { + if let Some(mut inner_shadow) = target.containing_shadow() { + loop { + let inner_shadow_host = inner_shadow.host(); + match inner_shadow_host.containing_shadow() { + Some(shadow) => { + if let Some(data) = shadow.style_data() { + if data.any_part_rule() { + f(data, shadow.host()) + } + } + // TODO: Could be more granular. + if !shadow.host().exports_any_part() { + break; + } + inner_shadow = shadow; + } + None => { + // TODO(emilio): Should probably distinguish with + // MatchesDocumentRules::{No,Yes,IfPart} or + // something so that we could skip some work. + doc_rules_apply = true; + break; + } + } + } + } + } + doc_rules_apply } diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index ab1fb88d7f2..6469d65f616 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -348,7 +348,9 @@ where return; } - let outer_shadow = inner_shadow.host().containing_shadow(); + + let inner_shadow_host = inner_shadow.host(); + let outer_shadow = inner_shadow_host.containing_shadow(); let part_rules = match outer_shadow { Some(shadow) => shadow .style_data() @@ -387,8 +389,6 @@ where shadow_cascade_order.inc(); } - let inner_shadow_host = inner_shadow.host(); - inner_shadow = match outer_shadow { Some(s) => s, None => break, // Nowhere to export to. diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 83db2ec4b17..56f36b9791f 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -1889,18 +1889,33 @@ impl CascadeData { self.host_rules.as_ref().and_then(|d| d.rules(pseudo)) } + /// Whether there's any host rule that could match in this scope. + pub fn any_host_rules(&self) -> bool { + self.host_rules.is_some() + } + /// Returns the slotted rule map for a given pseudo-element. #[inline] pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap> { self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo)) } + /// Whether there's any ::slotted rule that could match in this scope. + pub fn any_slotted_rule(&self) -> bool { + self.slotted_rules.is_some() + } + /// Returns the parts rule map for a given pseudo-element. #[inline] pub fn part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap> { self.part_rules.as_ref().and_then(|d| d.rules(pseudo)) } + /// Whether there's any ::part rule that could match in this scope. + pub fn any_part_rule(&self) -> bool { + self.part_rules.is_some() + } + /// Collects all the applicable media query results into `results`. /// /// This duplicates part of the logic in `add_stylesheet`, which is