mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibWeb: Bucket :is/where() selectors by tag name and ID as well
Instead of only bucketing these by class name, let's also bucket by tag name and ID. Reduces the number of selectors evaluated on https://tailwindcss.com/ from 2.9% to 1.9%.
This commit is contained in:
parent
49d2b11085
commit
5bb0f43b90
Notes:
github-actions[bot]
2024-09-09 18:13:12 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/5bb0f43b90a Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1345
1 changed files with 52 additions and 20 deletions
|
@ -2646,7 +2646,12 @@ void StyleComputer::build_rule_cache_if_needed() const
|
|||
const_cast<StyleComputer&>(*this).build_rule_cache();
|
||||
}
|
||||
|
||||
static Optional<FlyString> is_roundabout_selector_bucketable_as_class(CSS::Selector::SimpleSelector const& simple_selector)
|
||||
struct SimplifiedSelectorForBucketing {
|
||||
CSS::Selector::SimpleSelector::Type type;
|
||||
FlyString name;
|
||||
};
|
||||
|
||||
static Optional<SimplifiedSelectorForBucketing> is_roundabout_selector_bucketable_as_something_simpler(CSS::Selector::SimpleSelector const& simple_selector)
|
||||
{
|
||||
if (simple_selector.type != CSS::Selector::SimpleSelector::Type::PseudoClass)
|
||||
return {};
|
||||
|
@ -2665,10 +2670,16 @@ static Optional<FlyString> is_roundabout_selector_bucketable_as_class(CSS::Selec
|
|||
return {};
|
||||
|
||||
auto const& inner_simple_selector = compound_selector.simple_selectors.first();
|
||||
if (inner_simple_selector.type != CSS::Selector::SimpleSelector::Type::Class)
|
||||
return {};
|
||||
if (inner_simple_selector.type == CSS::Selector::SimpleSelector::Type::Class
|
||||
|| inner_simple_selector.type == CSS::Selector::SimpleSelector::Type::Id) {
|
||||
return SimplifiedSelectorForBucketing { inner_simple_selector.type, inner_simple_selector.name() };
|
||||
}
|
||||
|
||||
return inner_simple_selector.name();
|
||||
if (inner_simple_selector.type == CSS::Selector::SimpleSelector::Type::TagName) {
|
||||
return SimplifiedSelectorForBucketing { inner_simple_selector.type, inner_simple_selector.qualified_name().name.lowercase_name };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_cascade_origin(CascadeOrigin cascade_origin)
|
||||
|
@ -2723,32 +2734,53 @@ NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_casca
|
|||
// NOTE: We traverse the simple selectors in reverse order to make sure that class/ID buckets are preferred over tag buckets
|
||||
// in the common case of div.foo or div#foo selectors.
|
||||
bool added_to_bucket = false;
|
||||
|
||||
auto add_to_id_bucket = [&](FlyString const& name) {
|
||||
rule_cache->rules_by_id.ensure(name).append(move(matching_rule));
|
||||
++num_id_rules;
|
||||
added_to_bucket = true;
|
||||
};
|
||||
|
||||
auto add_to_class_bucket = [&](FlyString const& name) {
|
||||
rule_cache->rules_by_class.ensure(name).append(move(matching_rule));
|
||||
++num_class_rules;
|
||||
added_to_bucket = true;
|
||||
};
|
||||
|
||||
auto add_to_tag_name_bucket = [&](FlyString const& name) {
|
||||
rule_cache->rules_by_tag_name.ensure(name).append(move(matching_rule));
|
||||
++num_tag_name_rules;
|
||||
added_to_bucket = true;
|
||||
};
|
||||
|
||||
for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors.in_reverse()) {
|
||||
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Id) {
|
||||
rule_cache->rules_by_id.ensure(simple_selector.name()).append(move(matching_rule));
|
||||
++num_id_rules;
|
||||
added_to_bucket = true;
|
||||
add_to_id_bucket(simple_selector.name());
|
||||
break;
|
||||
}
|
||||
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Class) {
|
||||
rule_cache->rules_by_class.ensure(simple_selector.name()).append(move(matching_rule));
|
||||
++num_class_rules;
|
||||
added_to_bucket = true;
|
||||
break;
|
||||
}
|
||||
// NOTE: Selectors like `:is/where(.foo)` and `:is/where(.foo .bar)` are bucketed as class selectors for `foo` and `bar` respectively.
|
||||
if (auto class_ = is_roundabout_selector_bucketable_as_class(simple_selector); class_.has_value()) {
|
||||
rule_cache->rules_by_class.ensure(class_.value()).append(move(matching_rule));
|
||||
++num_class_rules;
|
||||
added_to_bucket = true;
|
||||
add_to_class_bucket(simple_selector.name());
|
||||
break;
|
||||
}
|
||||
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::TagName) {
|
||||
rule_cache->rules_by_tag_name.ensure(simple_selector.qualified_name().name.lowercase_name).append(move(matching_rule));
|
||||
++num_tag_name_rules;
|
||||
added_to_bucket = true;
|
||||
add_to_tag_name_bucket(simple_selector.qualified_name().name.lowercase_name);
|
||||
break;
|
||||
}
|
||||
// NOTE: Selectors like `:is/where(.foo)` and `:is/where(.foo .bar)` are bucketed as class selectors for `foo` and `bar` respectively.
|
||||
if (auto simplified = is_roundabout_selector_bucketable_as_something_simpler(simple_selector); simplified.has_value()) {
|
||||
if (simplified->type == CSS::Selector::SimpleSelector::Type::TagName) {
|
||||
add_to_tag_name_bucket(simplified->name);
|
||||
break;
|
||||
}
|
||||
if (simplified->type == CSS::Selector::SimpleSelector::Type::Class) {
|
||||
add_to_class_bucket(simplified->name);
|
||||
break;
|
||||
}
|
||||
if (simplified->type == CSS::Selector::SimpleSelector::Type::Id) {
|
||||
add_to_id_bucket(simplified->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!added_to_bucket) {
|
||||
if (matching_rule.contains_pseudo_element) {
|
||||
|
|
Loading…
Reference in a new issue