When a sheet's rightmost compound carries :first-child, :last-child,
or :only-child but no other class/tag/id/attr feature, the sheet
add/remove path can target the boundary children directly instead of
falling back to a whole-subtree invalidation.
The narrowing in extend_style_sheet_invalidation_set_with_style_rule
deliberately only kicks in when the structural pseudo is the only
feature in the rightmost compound. A selector like `.foo:first-child`
keeps targeting `.foo` rather than every first-child in the
document.
Adds matchers for :first-child / :last-child / :only-child in
InvalidationSetMatcher so the targeted walk can recognize them on
each candidate element.
@keyframes rules only affect elements that already reference the named
animation. Instead of falling back to a whole-subtree invalidation
when a sheet contains @keyframes, walk the sheet's @keyframes rules in
StyleSheetList::add_sheet/remove_sheet and reuse the existing per-rule
helper to dirty just the elements that reference each animation-name.
Broad shadow-root stylesheet changes already restyle the whole shadow
tree, but host-side fallout does not always need a document-wide
invalidation. Split the host-side reach classification so selectors
contained to the host subtree, such as `:host *` and `:host > *`,
invalidate the host, while sibling-escaping selectors such as
`:host + :has(*)` still invalidate the host's root.
Recognize sibling escapes through positive selector-list pseudos such as
`:is()` and `:where()` as well, including selectors like
`:is(:host) + :has(*)` and `:is(:host + .item)`.
This avoids turning host-contained shadow stylesheet changes into full
document style invalidations. On https://pomax.github.io/bezierinfo/,
this reduces the time to produce a layout tree from about 8.7s to 3.6s
on my machine.
Element.cpp still contained the CSS logic for deciding whether an
invalidation set references features present on an element. Move that
matcher into CSS::Invalidation::InvalidationSetMatcher.
The helper uses Element's public API for classes, id, attributes,
pseudo-class state, and removed-attribute tracking. This keeps Element
focused on DOM state while CSS::Invalidation owns selector feature
matching.
When a :has() mutation is known to come from a specific subtree, use
that subtree as the mutation root while walking observed ancestors.
Before dirtying an anchor and its non-subject descendants, check whether
any cached :has() rule for that anchor can observe the changed subtree.
This keeps unrelated descendant mutations from invalidating every rule
that merely contains :has().
CSSOM declaration mutations on style rules and nested declarations
do not change selector buckets, layer ordering, or keyframe sets stored
in rule caches. Keep those caches valid and only invalidate affected
styles, while leaving keyframe declaration mutations on the existing
cache-invalidating path.
Add coverage showing a CSSOM style declaration mutation is observed
through an already-built rule cache.
Avoid broad document invalidation when adding or removing ordinary
document-owned or shadow-owned stylesheets. Reuse the targeted
StyleSheetInvalidation path for style rules, including shadow-host
escapes, pseudo-element-only selectors, and trailing-universal cases.
Keep the broad path for sheet contents whose effects are not captured
by selector invalidation alone, including @property, @font-face,
@font-feature-values, @keyframes, imported sheets, and top-level @layer
blocks. Broad-path shadow-root sheets still reach host-side consumers
through their active-scope effects.
When invalidate_owners() runs on a stylesheet scoped to a shadow root,
we previously dirtied the host and its light-DOM side too broadly. That
forced restyles on nodes the shadow-scoped stylesheet cannot match.
Inspect the sheet's effective selectors and dependent features up front.
Only dirty assigned nodes, the host, the host root, or host-side
animation consumers when the sheet can actually reach them, while
keeping purely shadow-local mutations inside the shadow tree.
Handle inline stylesheet @keyframes insertions without falling back to
broad owner invalidation. Recompute only elements whose computed
animation-name already references the inserted keyframes name.
Document-scoped insertions still walk the shadow-including tree so
existing shadow trees pick up inherited animations, and shadow-root
stylesheets fan out through the host root so :host combinators can
refresh host-side consumers as well. Also introduce the shared
ShadowRootStylesheetEffects analysis so later stylesheet mutation paths
can reuse the same per-scope escape classification.
Avoid forcing a full style update when a connected inline <style> sheet
inserts an ordinary style rule. Build a targeted invalidation set from
the inserted rule and walk only the affected roots instead.
Introduce the shared StyleSheetInvalidation helper so later stylesheet
mutation paths can reuse the same selector analysis and root application
logic. It handles trailing-universal selectors, pseudo-element-only
rightmost compounds, and shadow-host escapes through ::slotted(...) and
:host combinators.
Keep the broad invalidate_owners() path for constructed stylesheets and
other sheet kinds whose TreeScope interactions still require it.