Files
ladybird/Libraries/LibWeb/CSS/StyleSheetInvalidation.h
Andreas Kling b6559d3846 LibWeb: Narrow inline stylesheet insertRule() invalidation
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.
2026-04-23 16:45:22 +02:00

62 lines
2.9 KiB
C++

/*
* Copyright (c) 2026, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/RefPtr.h>
#include <AK/Vector.h>
#include <LibGC/Ptr.h>
#include <LibWeb/CSS/Selector.h>
#include <LibWeb/CSS/StyleInvalidationData.h>
#include <LibWeb/DOM/StyleInvalidationReason.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
// Targeted invalidation plan derived from a stylesheet (or a single inserted rule) for the add/remove and insertRule
// paths. Carries a primary invalidation set plus anchor-based rules for selectors whose rightmost compound is
// pseudo-element-only or trailing-universal.
struct StyleSheetInvalidationSet {
InvalidationSet invalidation_set;
bool may_match_shadow_host { false };
bool may_match_light_dom_under_shadow_host { false };
struct PseudoElementInvalidationRule {
InvalidationSet anchor_set;
RefPtr<Selector> anchor_selector;
GC::Ptr<CSSStyleSheet const> style_sheet_for_rule;
};
struct TrailingUniversalInvalidationRule {
InvalidationSet anchor_set;
RefPtr<Selector> anchor_selector;
Selector::Combinator combinator { Selector::Combinator::None };
GC::Ptr<CSSStyleSheet const> style_sheet_for_rule;
};
Vector<PseudoElementInvalidationRule> pseudo_element_rules;
Vector<TrailingUniversalInvalidationRule> trailing_universal_rules;
};
// Extend `result` with the invalidation effects of `style_rule`'s selectors. Falls back to a whole-subtree
// invalidation flag inside `result` when a selector is not amenable to targeted invalidation.
void extend_style_sheet_invalidation_set_with_style_rule(StyleSheetInvalidationSet& result, CSSStyleRule const& style_rule);
// Shadow-root rules can escape the shadow tree either through ::slotted(...) or through :host with a combinator to
// another compound, such as :host > * or :host + .foo. Those selectors must fan out invalidation to the host side
// instead of treating the change as shadow-local.
bool selector_may_match_light_dom_under_shadow_host(Selector const&);
WEB_API bool selector_may_match_light_dom_under_shadow_host(StringView selector_text);
// Apply a built invalidation set to `root` (a Document or a ShadowRoot). When `force_broad_invalidation` is true,
// schedule a tree-wide restyle regardless of the targeted set; this is used when the sheet contains rule kinds (such
// as @property or @keyframes) whose effects are not captured by selector invalidation alone.
void invalidate_root_for_style_sheet_change(DOM::Node& root, StyleSheetInvalidationSet const&, DOM::StyleInvalidationReason, bool force_broad_invalidation = false);
// Apply a targeted invalidation to all documents and shadow roots that own `style_sheet` in response to inserting
// `style_rule` into it.
void invalidate_owners_for_inserted_style_rule(CSSStyleSheet const& style_sheet, CSSStyleRule const& style_rule, DOM::StyleInvalidationReason);
}