mirror of
https://github.com/lexmount/moli.git
synced 2026-10-08 08:01:01 +00:00
fix(cssom): invalidate nested declaration mutations
This commit is contained in:
@@ -912,7 +912,7 @@ impl LiveStylesheet {
|
||||
return None;
|
||||
};
|
||||
let ancestor_path_len = rule_path.len().saturating_sub(1);
|
||||
Some(LiveStylesheetRuleMutation::new(
|
||||
Some(Self::rule_mutation_for_cascade(
|
||||
rule,
|
||||
self.css_rule_ancestors_at_path(&rule_path[..ancestor_path_len])?,
|
||||
change_kind,
|
||||
@@ -925,13 +925,36 @@ impl LiveStylesheet {
|
||||
parent_path: &[usize],
|
||||
change_kind: RuleChangeKind,
|
||||
) -> Option<LiveStylesheetRuleMutation> {
|
||||
Some(LiveStylesheetRuleMutation::new(
|
||||
Some(Self::rule_mutation_for_cascade(
|
||||
rule,
|
||||
self.css_rule_ancestors_at_path(parent_path)?,
|
||||
change_kind,
|
||||
))
|
||||
}
|
||||
|
||||
fn rule_mutation_for_cascade(
|
||||
rule: CssRule,
|
||||
ancestors: Vec<CssRule>,
|
||||
change_kind: RuleChangeKind,
|
||||
) -> LiveStylesheetRuleMutation {
|
||||
if matches!(&rule, CssRule::NestedDeclarations(_))
|
||||
&& let Some(style_index) = ancestors
|
||||
.iter()
|
||||
.rposition(|ancestor| matches!(ancestor, CssRule::Style(_)))
|
||||
{
|
||||
// Nested declarations inherit their selector from the nearest
|
||||
// enclosing style rule. Stylo therefore does not collect ordinary
|
||||
// element invalidations from the declaration rule itself. Report
|
||||
// the effective declaration change on that selector-bearing rule.
|
||||
return LiveStylesheetRuleMutation::new(
|
||||
ancestors[style_index].clone(),
|
||||
ancestors[..style_index].to_vec(),
|
||||
RuleChangeKind::StyleRuleDeclarations,
|
||||
);
|
||||
}
|
||||
LiveStylesheetRuleMutation::new(rule, ancestors, change_kind)
|
||||
}
|
||||
|
||||
fn css_rule_ancestors_at_path(&self, path: &[usize]) -> Option<Vec<CssRule>> {
|
||||
let mut ancestors = Vec::with_capacity(path.len());
|
||||
for depth in 1..=path.len() {
|
||||
|
||||
@@ -3254,6 +3254,73 @@ getComputedStyle(document.querySelector('.nested-journal-target')).color;
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_declaration_mutations_invalidate_their_ancestor_style_selector() {
|
||||
let mut vm = new_storage_test_vm("https://nested-declaration-invalidation.test/");
|
||||
|
||||
assert_eq!(
|
||||
vm.eval(
|
||||
r#"
|
||||
const style = document.createElement('style');
|
||||
style.textContent = 'div { z-index: 1; &.test { } }';
|
||||
(document.head || document.documentElement || document).appendChild(style);
|
||||
const target = document.createElement('div');
|
||||
target.className = 'test';
|
||||
(document.body || document.documentElement || document).appendChild(target);
|
||||
globalThis.__nestedDeclarationRule = style.sheet.cssRules[0];
|
||||
globalThis.__nestedDeclarationTarget = target;
|
||||
getComputedStyle(target).zIndex;
|
||||
"#,
|
||||
)
|
||||
.expect("nested declaration invalidation setup should evaluate"),
|
||||
"1"
|
||||
);
|
||||
crate::style_engine::reset_live_stylesheet_update_counts_for_test();
|
||||
|
||||
assert_eq!(
|
||||
vm.eval(
|
||||
r#"
|
||||
const rule = globalThis.__nestedDeclarationRule;
|
||||
const mutationTarget = globalThis.__nestedDeclarationTarget;
|
||||
const states = [];
|
||||
|
||||
rule.insertRule('z-index: 3;', 0);
|
||||
const declarations = rule.cssRules[0];
|
||||
states.push(declarations instanceof CSSNestedDeclarations);
|
||||
states.push(getComputedStyle(mutationTarget).zIndex);
|
||||
|
||||
declarations.style.zIndex = '4';
|
||||
states.push(getComputedStyle(mutationTarget).zIndex);
|
||||
|
||||
rule.deleteRule(0);
|
||||
states.push(getComputedStyle(mutationTarget).zIndex);
|
||||
|
||||
rule.insertRule('@media all { a { } }', 1);
|
||||
const media = rule.cssRules[1];
|
||||
media.insertRule('z-index: 5;', 0);
|
||||
states.push(media.cssRules[0] instanceof CSSNestedDeclarations);
|
||||
states.push(getComputedStyle(mutationTarget).zIndex);
|
||||
|
||||
media.deleteRule(0);
|
||||
states.push(getComputedStyle(mutationTarget).zIndex);
|
||||
states.join('|');
|
||||
"#,
|
||||
)
|
||||
.expect("nested declaration mutations should invalidate ancestor selectors"),
|
||||
"true|3|4|1|true|5|1"
|
||||
);
|
||||
assert_eq!(
|
||||
crate::style_engine::exact_rule_change_notification_count_for_test(),
|
||||
6,
|
||||
"nested declaration changes should remain exact journal updates",
|
||||
);
|
||||
assert_eq!(
|
||||
crate::style_engine::full_cascade_update_fallback_count_for_test(),
|
||||
0,
|
||||
"nested declaration changes must not rebuild an entire stylesheet",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn computed_style_wrapper_reflects_style_element_media_mutations() {
|
||||
let mut vm = new_storage_test_vm("https://style-media-computed-wrapper-refresh.test/");
|
||||
|
||||
Reference in New Issue
Block a user