When an element was affected by :has() in subject position, pending :has() mutation invalidation also applied the pseudo-class invalidation plan for that element. If the same element had ever been observed in a non-subject :has() selector, that plan could invalidate the element's whole descendant subtree even when the mutation could only require the subject element itself to recompute style. Keep subject-position :has() invalidation to the element itself, and run the descendant fanout only for non-subject involvement after the existing mutation feature filter says that fanout may be affected. Track the strongest invalidation applied to each anchor, so a later batched mutation can still upgrade earlier anchor-only work to a descendant fanout. Extend the filter to treat known state pseudo-classes as concrete mutation features, so a :hover mutation does not conservatively match unrelated selectors such as :has(dialog:modal). Scope boundary selectors are kept conservative where needed: when an @scope boundary contains :has(), the scope root's match can activate or deactivate style rules for descendants, so it still records descendant involvement. Add coverage for unrelated hover and batched mutation cases on elements whose ancestors have both subject and non-subject :has() involvement, ensuring descendant no-op recomputation stays bounded without dropping required descendant fanout.
31 lines
670 B
C++
31 lines
670 B
C++
/*
|
|
* Copyright (c) 2026-present, the Ladybird developers
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibWeb/DOM/StyleInvalidationReason.h>
|
|
|
|
namespace Web::DOM {
|
|
|
|
class Document;
|
|
class Element;
|
|
class Node;
|
|
|
|
}
|
|
|
|
namespace Web::CSS::Invalidation {
|
|
|
|
enum class DescendantHasInvalidation {
|
|
No,
|
|
Yes,
|
|
};
|
|
|
|
void invalidate_element_if_affected_by_has(DOM::Element&, DescendantHasInvalidation = DescendantHasInvalidation::Yes);
|
|
void invalidate_style_for_pending_has_mutations(DOM::Document&);
|
|
void schedule_has_invalidation_for_node(DOM::Node&, DOM::StyleInvalidationReason);
|
|
void schedule_has_invalidation_for_same_parent_move(DOM::Node&);
|
|
|
|
}
|