Skip to content
Permalink
Browse files

style: Invalidate shadow part pseudo-class styles correctly.

I was going to send a test for `:focus` via wpt, but then realized it was
probably not spec-compliant with the new rules people want to follow for
:focus, so I filed w3c/csswg-drafts#4555 instead.

Testing `:hover` / `:active` via wpt looked quite a bit of a hassle.

Differential Revision: https://phabricator.services.mozilla.com/D55591
  • Loading branch information
emilio committed Dec 9, 2019
1 parent 6973317 commit 7cd59da2a097863e194189268695ed75dc5a0a70
Showing with 53 additions and 4 deletions.
  1. +35 −1 components/style/dom.rs
  2. +3 −3 components/style/rule_collector.rs
  3. +15 −0 components/style/stylist.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
}

@@ -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.
@@ -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<Rule>> {
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

0 comments on commit 7cd59da

Please sign in to comment.
You can’t perform that action at this time.