mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-27 18:17:22 +02:00
LibWeb: Stop :has() invalidation walk when out of :has() scope
A DOM mutation under a document that uses any :has() rule currently walks every ancestor up to the root, invoking invalidate_style_if_ affected_by_has() on each. Most of those ancestors have nothing to do with :has(), so the work scales linearly with DOM depth. Introduce an in_has_scope flag on Element, set while evaluating :has() arguments for invalidation metadata. StyleScope's upward invalidation walk now terminates at the first element that is neither in :has() scope nor a :has() anchor, so it only traverses the region where some :has() rule might actually care about the change. Keep the existing fast :has() matching paths for normal selector matching, but bypass them while collecting per-element metadata so the scope markers still get populated. Node insertion also schedules the parent for the :has() walk so newly inserted nodes still reach the real anchor. The css-has-invalidation suite adds focused coverage for these shapes and updates the expected counters to reflect the shorter walks.
This commit is contained in:
committed by
Alexander Kalenik
parent
029b4998e5
commit
85ff13870f
Notes:
github-actions[bot]
2026-04-20 11:21:54 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/85ff13870f5 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8982
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script src="_helpers.js"></script>
|
||||
<style>
|
||||
/* Two different :has() rules on the same anchor. Each has a different
|
||||
argument, so changes to either argument class should trigger match
|
||||
re-evaluation. */
|
||||
.anchor:has(.red) { color: red; }
|
||||
.anchor:has(.blue) { background: blue; }
|
||||
</style>
|
||||
<div class="anchor" id="anchor">
|
||||
<span id="target">target</span>
|
||||
</div>
|
||||
<script>
|
||||
test(() => {
|
||||
settleAndReset();
|
||||
|
||||
document.getElementById("target").classList.add("red");
|
||||
getComputedStyle(document.getElementById("anchor")).color;
|
||||
printCounters("add .red (only :has(.red) flips)");
|
||||
|
||||
internals.resetStyleInvalidationCounters();
|
||||
|
||||
document.getElementById("target").classList.add("blue");
|
||||
getComputedStyle(document.getElementById("anchor")).color;
|
||||
printCounters("add .blue (only :has(.blue) flips, .red stable)");
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user