LibWeb: Add test-only counters for :has() invalidation work

Introduce a small set of counters on Document that track the work done
while processing :has() invalidation: how often the upward walk runs,
how many elements it visits, how often matches_has_pseudo_class() is
invoked, how well the per-pass result cache performs, and how many
elements transition from clean to needs-style-update.

Expose the counters through internals so tests can assert precise bounds
on the invalidation work triggered by a mutation, which regular
reference tests cannot express.

Add a css-has-invalidation test suite that covers subject-position,
non-subject-position, sibling-combinator, and no-:has() cases. The
baseline tests share a helper script so later coverage can reuse the
same counter-printing path.

The counters are test-only observation; they do not affect style
computation itself.
This commit is contained in:
Andreas Kling
2026-04-18 19:04:13 +02:00
committed by Alexander Kalenik
parent e5d4c5cce8
commit a72fae8d36
Notes: github-actions[bot] 2026-04-20 11:22:35 +00:00
20 changed files with 286 additions and 1 deletions

View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<script src="../include.js"></script>
<script src="_helpers.js"></script>
<style>
/* Many sibling anchors with the same :has() selector. Each sibling will be
tested during a single style pass. The HasResultCache should absorb repeat
matches against the same anchor. */
.anchor:has(.match) { color: red; }
.anchor:has(.match) + .anchor { color: blue; }
</style>
<div id="container">
<div class="anchor"><span>x</span></div>
<div class="anchor"><span>x</span></div>
<div class="anchor"><span>x</span></div>
<div class="anchor"><span>x</span></div>
<div class="anchor"><span class="match" id="target">x</span></div>
</div>
<script>
test(() => {
getComputedStyle(document.getElementById("container")).color;
internals.resetStyleInvalidationCounters();
// Removing the .match class forces re-match on all anchors in the next pass.
document.getElementById("target").classList.remove("match");
getComputedStyle(document.getElementById("container")).color;
printCounters("after remove .match");
});
</script>