Changing :active or :open used the broad style invalidation path, so
large subtrees were recomputed even when only the target element and
selector-matched relatives could be affected.
Reuse the :has() feature collector to keep conservative fallback for
observable :has() cases, then use pseudo-class property invalidation
for the common targeted path.
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.
Node.cpp currently knows too much about selector invalidation metadata
when deciding whether subtree mutations can affect :has() selectors.
Pull that logic into CSS/Invalidation/HasMutationFeatureCollector so DOM
mutation code can ask a focused helper instead of inspecting
StyleInvalidationData directly.
This is a behavior-preserving extraction. It keeps the existing
conservative fallbacks for featureless subtree-sensitive selectors and
still uses the existing element property matching helper for
pseudo-class metadata.