mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-24 19:28:48 +00:00
LibWeb: Filter :hover selectors early for elements that aren't hovered
Some websites (like vercel.com...) have a *lot* of :hover selectors that we can simply skip for any element that isn't currently hovered.
This commit is contained in:
parent
5bb0f43b90
commit
ef4f5ac8fb
Notes:
github-actions[bot]
2024-09-09 18:13:06 +00:00
Author: https://github.com/awesomekling
Commit: ef4f5ac8fb
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1345
4 changed files with 33 additions and 1 deletions
|
@ -140,7 +140,7 @@ static inline bool matches_link_pseudo_class(DOM::Element const& element)
|
||||||
return element.has_attribute(HTML::AttributeNames::href);
|
return element.has_attribute(HTML::AttributeNames::href);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool matches_hover_pseudo_class(DOM::Element const& element)
|
bool matches_hover_pseudo_class(DOM::Element const& element)
|
||||||
{
|
{
|
||||||
auto* hovered_node = element.document().hovered_node();
|
auto* hovered_node = element.document().hovered_node();
|
||||||
if (!hovered_node)
|
if (!hovered_node)
|
||||||
|
|
|
@ -21,4 +21,6 @@ bool matches(CSS::Selector const&, Optional<CSS::CSSStyleSheet const&> style_she
|
||||||
[[nodiscard]] bool fast_matches(CSS::Selector const&, Optional<CSS::CSSStyleSheet const&> style_sheet_for_rule, DOM::Element const&, JS::GCPtr<DOM::Element const> shadow_host);
|
[[nodiscard]] bool fast_matches(CSS::Selector const&, Optional<CSS::CSSStyleSheet const&> style_sheet_for_rule, DOM::Element const&, JS::GCPtr<DOM::Element const> shadow_host);
|
||||||
[[nodiscard]] bool can_use_fast_matches(CSS::Selector const&);
|
[[nodiscard]] bool can_use_fast_matches(CSS::Selector const&);
|
||||||
|
|
||||||
|
[[nodiscard]] bool matches_hover_pseudo_class(DOM::Element const&);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,16 +356,22 @@ Vector<MatchingRule> StyleComputer::collect_matching_rules(DOM::Element const& e
|
||||||
|
|
||||||
auto const& rule_cache = rule_cache_for_cascade_origin(cascade_origin);
|
auto const& rule_cache = rule_cache_for_cascade_origin(cascade_origin);
|
||||||
|
|
||||||
|
bool is_hovered = SelectorEngine::matches_hover_pseudo_class(element);
|
||||||
|
|
||||||
Vector<MatchingRule, 512> rules_to_run;
|
Vector<MatchingRule, 512> rules_to_run;
|
||||||
auto add_rules_to_run = [&](Vector<MatchingRule> const& rules) {
|
auto add_rules_to_run = [&](Vector<MatchingRule> const& rules) {
|
||||||
rules_to_run.grow_capacity(rules_to_run.size() + rules.size());
|
rules_to_run.grow_capacity(rules_to_run.size() + rules.size());
|
||||||
if (pseudo_element.has_value()) {
|
if (pseudo_element.has_value()) {
|
||||||
for (auto const& rule : rules) {
|
for (auto const& rule : rules) {
|
||||||
|
if (rule.must_be_hovered && !is_hovered)
|
||||||
|
continue;
|
||||||
if (rule.contains_pseudo_element && filter_namespace_rule(element, rule) && filter_layer(qualified_layer_name, rule))
|
if (rule.contains_pseudo_element && filter_namespace_rule(element, rule) && filter_layer(qualified_layer_name, rule))
|
||||||
rules_to_run.unchecked_append(rule);
|
rules_to_run.unchecked_append(rule);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto const& rule : rules) {
|
for (auto const& rule : rules) {
|
||||||
|
if (rule.must_be_hovered && !is_hovered)
|
||||||
|
continue;
|
||||||
if (!rule.contains_pseudo_element && filter_namespace_rule(element, rule) && filter_layer(qualified_layer_name, rule))
|
if (!rule.contains_pseudo_element && filter_namespace_rule(element, rule) && filter_layer(qualified_layer_name, rule))
|
||||||
rules_to_run.unchecked_append(rule);
|
rules_to_run.unchecked_append(rule);
|
||||||
}
|
}
|
||||||
|
@ -2692,6 +2698,7 @@ NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_casca
|
||||||
size_t num_pseudo_element_rules = 0;
|
size_t num_pseudo_element_rules = 0;
|
||||||
size_t num_root_rules = 0;
|
size_t num_root_rules = 0;
|
||||||
size_t num_attribute_rules = 0;
|
size_t num_attribute_rules = 0;
|
||||||
|
size_t num_hover_rules = 0;
|
||||||
|
|
||||||
Vector<MatchingRule> matching_rules;
|
Vector<MatchingRule> matching_rules;
|
||||||
size_t style_sheet_index = 0;
|
size_t style_sheet_index = 0;
|
||||||
|
@ -2711,6 +2718,7 @@ NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_casca
|
||||||
cascade_origin,
|
cascade_origin,
|
||||||
false,
|
false,
|
||||||
SelectorEngine::can_use_fast_matches(selector),
|
SelectorEngine::can_use_fast_matches(selector),
|
||||||
|
false,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool contains_root_pseudo_class = false;
|
bool contains_root_pseudo_class = false;
|
||||||
|
@ -2729,6 +2737,27 @@ NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_casca
|
||||||
++num_root_rules;
|
++num_root_rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!matching_rule.must_be_hovered) {
|
||||||
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass && simple_selector.pseudo_class().type == CSS::PseudoClass::Hover) {
|
||||||
|
matching_rule.must_be_hovered = true;
|
||||||
|
++num_hover_rules;
|
||||||
|
}
|
||||||
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass
|
||||||
|
&& (simple_selector.pseudo_class().type == CSS::PseudoClass::Is
|
||||||
|
|| simple_selector.pseudo_class().type == CSS::PseudoClass::Where)) {
|
||||||
|
auto const& argument_selectors = simple_selector.pseudo_class().argument_selector_list;
|
||||||
|
|
||||||
|
if (argument_selectors.size() == 1) {
|
||||||
|
auto const& simple_argument_selector = argument_selectors.first()->compound_selectors().last().simple_selectors.last();
|
||||||
|
if (simple_argument_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass
|
||||||
|
&& simple_argument_selector.pseudo_class().type == CSS::PseudoClass::Hover) {
|
||||||
|
matching_rule.must_be_hovered = true;
|
||||||
|
++num_hover_rules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We traverse the simple selectors in reverse order to make sure that class/ID buckets are preferred over tag buckets
|
// NOTE: We traverse the simple selectors in reverse order to make sure that class/ID buckets are preferred over tag buckets
|
||||||
|
|
|
@ -92,6 +92,7 @@ struct MatchingRule {
|
||||||
CascadeOrigin cascade_origin;
|
CascadeOrigin cascade_origin;
|
||||||
bool contains_pseudo_element { false };
|
bool contains_pseudo_element { false };
|
||||||
bool can_use_fast_matches { false };
|
bool can_use_fast_matches { false };
|
||||||
|
bool must_be_hovered { false };
|
||||||
bool skip { false };
|
bool skip { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue