mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-24 12:02:51 +00:00
LibWeb: Make :hover invalidation logic reusable for all pseudo classes
We achieve this by keeping track of all checked pseudo class selectors in the SelectorEngine code. We also give StyleComputer per-pseudo-class rule caches.
This commit is contained in:
parent
ed35f9e7c2
commit
e1777f6e79
Notes:
github-actions[bot]
2025-04-17 17:47:22 +00:00
Author: https://github.com/awesomekling
Commit: e1777f6e79
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4388
13 changed files with 134 additions and 59 deletions
|
@ -422,10 +422,10 @@ RuleCache const* StyleComputer::rule_cache_for_cascade_origin(CascadeOrigin casc
|
|||
return true;
|
||||
}
|
||||
|
||||
RuleCache const& StyleComputer::get_hover_rules() const
|
||||
RuleCache const& StyleComputer::get_pseudo_class_rule_cache(PseudoClass pseudo_class) const
|
||||
{
|
||||
build_rule_cache_if_needed();
|
||||
return *m_hover_rule_cache;
|
||||
return *m_pseudo_class_rule_cache[to_underlying(pseudo_class)];
|
||||
}
|
||||
|
||||
InvalidationSet StyleComputer::invalidation_set_for_properties(Vector<InvalidationSet::Property> const& properties) const
|
||||
|
@ -472,7 +472,7 @@ bool StyleComputer::invalidation_property_used_in_has_selector(InvalidationSet::
|
|||
return false;
|
||||
}
|
||||
|
||||
Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element const& element, CascadeOrigin cascade_origin, Optional<CSS::PseudoElement> pseudo_element, bool& did_match_any_hover_rules, FlyString const& qualified_layer_name) const
|
||||
Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element const& element, CascadeOrigin cascade_origin, Optional<CSS::PseudoElement> pseudo_element, PseudoClassBitmap& attempted_pseudo_class_matches, FlyString const& qualified_layer_name) const
|
||||
{
|
||||
auto const& root_node = element.root();
|
||||
auto shadow_root = is<DOM::ShadowRoot>(root_node) ? static_cast<DOM::ShadowRoot const*>(&root_node) : nullptr;
|
||||
|
@ -567,8 +567,7 @@ Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element c
|
|||
.collect_per_element_selector_involvement_metadata = true,
|
||||
};
|
||||
ScopeGuard guard = [&] {
|
||||
if (context.did_match_any_hover_rules)
|
||||
did_match_any_hover_rules = true;
|
||||
attempted_pseudo_class_matches |= context.attempted_pseudo_class_matches;
|
||||
};
|
||||
if (!SelectorEngine::matches(selector, element, shadow_host_to_use, context, pseudo_element))
|
||||
continue;
|
||||
|
@ -1566,24 +1565,24 @@ void StyleComputer::start_needed_transitions(ComputedProperties const& previous_
|
|||
|
||||
// https://www.w3.org/TR/css-cascade/#cascading
|
||||
// https://drafts.csswg.org/css-cascade-5/#layering
|
||||
GC::Ref<CascadedProperties> StyleComputer::compute_cascaded_values(DOM::Element& element, Optional<CSS::PseudoElement> pseudo_element, bool& did_match_any_pseudo_element_rules, bool& did_match_any_hover_rules, ComputeStyleMode mode) const
|
||||
GC::Ref<CascadedProperties> StyleComputer::compute_cascaded_values(DOM::Element& element, Optional<CSS::PseudoElement> pseudo_element, bool& did_match_any_pseudo_element_rules, PseudoClassBitmap& attempted_pseudo_class_matches, ComputeStyleMode mode) const
|
||||
{
|
||||
auto cascaded_properties = m_document->heap().allocate<CascadedProperties>();
|
||||
|
||||
// First, we collect all the CSS rules whose selectors match `element`:
|
||||
MatchingRuleSet matching_rule_set;
|
||||
matching_rule_set.user_agent_rules = collect_matching_rules(element, CascadeOrigin::UserAgent, pseudo_element, did_match_any_hover_rules);
|
||||
matching_rule_set.user_agent_rules = collect_matching_rules(element, CascadeOrigin::UserAgent, pseudo_element, attempted_pseudo_class_matches);
|
||||
sort_matching_rules(matching_rule_set.user_agent_rules);
|
||||
matching_rule_set.user_rules = collect_matching_rules(element, CascadeOrigin::User, pseudo_element, did_match_any_hover_rules);
|
||||
matching_rule_set.user_rules = collect_matching_rules(element, CascadeOrigin::User, pseudo_element, attempted_pseudo_class_matches);
|
||||
sort_matching_rules(matching_rule_set.user_rules);
|
||||
// @layer-ed author rules
|
||||
for (auto const& layer_name : m_qualified_layer_names_in_order) {
|
||||
auto layer_rules = collect_matching_rules(element, CascadeOrigin::Author, pseudo_element, did_match_any_hover_rules, layer_name);
|
||||
auto layer_rules = collect_matching_rules(element, CascadeOrigin::Author, pseudo_element, attempted_pseudo_class_matches, layer_name);
|
||||
sort_matching_rules(layer_rules);
|
||||
matching_rule_set.author_rules.append({ layer_name, layer_rules });
|
||||
}
|
||||
// Un-@layer-ed author rules
|
||||
auto unlayered_author_rules = collect_matching_rules(element, CascadeOrigin::Author, pseudo_element, did_match_any_hover_rules);
|
||||
auto unlayered_author_rules = collect_matching_rules(element, CascadeOrigin::Author, pseudo_element, attempted_pseudo_class_matches);
|
||||
sort_matching_rules(unlayered_author_rules);
|
||||
matching_rule_set.author_rules.append({ {}, unlayered_author_rules });
|
||||
|
||||
|
@ -2427,8 +2426,8 @@ GC::Ptr<ComputedProperties> StyleComputer::compute_style_impl(DOM::Element& elem
|
|||
|
||||
// 1. Perform the cascade. This produces the "specified style"
|
||||
bool did_match_any_pseudo_element_rules = false;
|
||||
bool did_match_any_hover_rules = false;
|
||||
auto cascaded_properties = compute_cascaded_values(element, pseudo_element, did_match_any_pseudo_element_rules, did_match_any_hover_rules, mode);
|
||||
PseudoClassBitmap attempted_pseudo_class_matches;
|
||||
auto cascaded_properties = compute_cascaded_values(element, pseudo_element, did_match_any_pseudo_element_rules, attempted_pseudo_class_matches, mode);
|
||||
|
||||
element.set_cascaded_properties(pseudo_element, cascaded_properties);
|
||||
|
||||
|
@ -2462,8 +2461,7 @@ GC::Ptr<ComputedProperties> StyleComputer::compute_style_impl(DOM::Element& elem
|
|||
}
|
||||
|
||||
auto computed_properties = compute_properties(element, pseudo_element, cascaded_properties);
|
||||
if (did_match_any_hover_rules)
|
||||
computed_properties->set_did_match_any_hover_rules();
|
||||
computed_properties->set_attempted_pseudo_class_matches(attempted_pseudo_class_matches);
|
||||
return computed_properties;
|
||||
}
|
||||
|
||||
|
@ -2834,10 +2832,17 @@ void StyleComputer::make_rule_cache_for_cascade_origin(CascadeOrigin cascade_ori
|
|||
}
|
||||
}
|
||||
|
||||
if (selector.contains_hover_pseudo_class()) {
|
||||
// For hover rule cache we intentionally pass pseudo_element as None, because we don't want to bucket hover rules by pseudo element type
|
||||
m_hover_rule_cache->add_rule(matching_rule, {}, contains_root_pseudo_class);
|
||||
for (size_t i = 0; i < to_underlying(PseudoClass::__Count); ++i) {
|
||||
auto pseudo_class = static_cast<PseudoClass>(i);
|
||||
// If we're not building a rule cache for this pseudo class, just ignore it.
|
||||
if (!m_pseudo_class_rule_cache[i])
|
||||
continue;
|
||||
if (selector.contains_pseudo_class(pseudo_class)) {
|
||||
// For pseudo class rule caches we intentionally pass no pseudo-element, because we don't want to bucket pseudo class rules by pseudo-element type.
|
||||
m_pseudo_class_rule_cache[i]->add_rule(matching_rule, {}, contains_root_pseudo_class);
|
||||
}
|
||||
}
|
||||
|
||||
rule_cache.add_rule(matching_rule, pseudo_element, contains_root_pseudo_class);
|
||||
}
|
||||
++rule_index;
|
||||
|
@ -2965,7 +2970,14 @@ void StyleComputer::build_rule_cache()
|
|||
|
||||
build_qualified_layer_names_cache();
|
||||
|
||||
m_hover_rule_cache = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::Hover)] = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::Active)] = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::Focus)] = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::FocusWithin)] = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::FocusVisible)] = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::Target)] = make<RuleCache>();
|
||||
m_pseudo_class_rule_cache[to_underlying(PseudoClass::TargetWithin)] = make<RuleCache>();
|
||||
|
||||
make_rule_cache_for_cascade_origin(CascadeOrigin::Author, *m_selector_insights);
|
||||
make_rule_cache_for_cascade_origin(CascadeOrigin::User, *m_selector_insights);
|
||||
make_rule_cache_for_cascade_origin(CascadeOrigin::UserAgent, *m_selector_insights);
|
||||
|
@ -2985,7 +2997,7 @@ void StyleComputer::invalidate_rule_cache()
|
|||
// If we are sure that it's safe, we could keep it as an optimization.
|
||||
m_user_agent_rule_cache = nullptr;
|
||||
|
||||
m_hover_rule_cache = nullptr;
|
||||
m_pseudo_class_rule_cache = {};
|
||||
m_style_invalidation_data = nullptr;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue