mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-01 05:39:11 +00:00
LibWeb: Collect interesting document-wide insights about CSS selectors
Starting out with these two things: - Whether any :has() selectors are present - The set of all names referenced by attribute selectors
This commit is contained in:
parent
dc8343cc23
commit
6983c65c54
Notes:
github-actions[bot]
2024-12-23 16:06:10 +00:00
Author: https://github.com/awesomekling
Commit: 6983c65c54
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3023
2 changed files with 42 additions and 22 deletions
|
@ -2503,24 +2503,26 @@ static Optional<SimplifiedSelectorForBucketing> is_roundabout_selector_bucketabl
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool contains_has_pseudo_class(Selector const& selector)
|
void StyleComputer::collect_selector_insights(Selector const& selector, SelectorInsights& insights)
|
||||||
{
|
{
|
||||||
for (auto const& compound_selector : selector.compound_selectors()) {
|
for (auto const& compound_selector : selector.compound_selectors()) {
|
||||||
for (auto const& simple_selector : compound_selector.simple_selectors) {
|
for (auto const& simple_selector : compound_selector.simple_selectors) {
|
||||||
if (simple_selector.type != CSS::Selector::SimpleSelector::Type::PseudoClass)
|
if (simple_selector.type == Selector::SimpleSelector::Type::Attribute) {
|
||||||
continue;
|
insights.all_names_used_in_attribute_selectors.set(simple_selector.attribute().qualified_name.name.lowercase_name);
|
||||||
if (simple_selector.pseudo_class().type == CSS::PseudoClass::Has)
|
}
|
||||||
return true;
|
if (simple_selector.type == Selector::SimpleSelector::Type::PseudoClass) {
|
||||||
for (auto const& argument_selector : simple_selector.pseudo_class().argument_selector_list) {
|
if (simple_selector.pseudo_class().type == PseudoClass::Has) {
|
||||||
if (contains_has_pseudo_class(argument_selector))
|
insights.has_has_selectors = true;
|
||||||
return true;
|
}
|
||||||
|
for (auto const& argument_selector : simple_selector.pseudo_class().argument_selector_list) {
|
||||||
|
collect_selector_insights(*argument_selector, insights);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_cascade_origin(CascadeOrigin cascade_origin)
|
NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_cascade_origin(CascadeOrigin cascade_origin, SelectorInsights& insights)
|
||||||
{
|
{
|
||||||
auto rule_cache = make<RuleCache>();
|
auto rule_cache = make<RuleCache>();
|
||||||
|
|
||||||
|
@ -2563,8 +2565,7 @@ NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_casca
|
||||||
bool contains_root_pseudo_class = false;
|
bool contains_root_pseudo_class = false;
|
||||||
Optional<CSS::Selector::PseudoElement::Type> pseudo_element;
|
Optional<CSS::Selector::PseudoElement::Type> pseudo_element;
|
||||||
|
|
||||||
if (!rule_cache->has_has_selectors)
|
collect_selector_insights(selector, insights);
|
||||||
rule_cache->has_has_selectors = contains_has_pseudo_class(selector);
|
|
||||||
|
|
||||||
for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) {
|
for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) {
|
||||||
if (!matching_rule.contains_pseudo_element) {
|
if (!matching_rule.contains_pseudo_element) {
|
||||||
|
@ -2807,17 +2808,17 @@ void StyleComputer::build_qualified_layer_names_cache()
|
||||||
|
|
||||||
void StyleComputer::build_rule_cache()
|
void StyleComputer::build_rule_cache()
|
||||||
{
|
{
|
||||||
|
m_selector_insights = make<SelectorInsights>();
|
||||||
|
|
||||||
if (auto user_style_source = document().page().user_style(); user_style_source.has_value()) {
|
if (auto user_style_source = document().page().user_style(); user_style_source.has_value()) {
|
||||||
m_user_style_sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingContext(document()), user_style_source.value()));
|
m_user_style_sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingContext(document()), user_style_source.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
build_qualified_layer_names_cache();
|
build_qualified_layer_names_cache();
|
||||||
|
|
||||||
m_author_rule_cache = make_rule_cache_for_cascade_origin(CascadeOrigin::Author);
|
m_author_rule_cache = make_rule_cache_for_cascade_origin(CascadeOrigin::Author, *m_selector_insights);
|
||||||
m_user_rule_cache = make_rule_cache_for_cascade_origin(CascadeOrigin::User);
|
m_user_rule_cache = make_rule_cache_for_cascade_origin(CascadeOrigin::User, *m_selector_insights);
|
||||||
m_user_agent_rule_cache = make_rule_cache_for_cascade_origin(CascadeOrigin::UserAgent);
|
m_user_agent_rule_cache = make_rule_cache_for_cascade_origin(CascadeOrigin::UserAgent, *m_selector_insights);
|
||||||
|
|
||||||
m_has_has_selectors = m_author_rule_cache->has_has_selectors || m_user_rule_cache->has_has_selectors || m_user_agent_rule_cache->has_has_selectors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleComputer::invalidate_rule_cache()
|
void StyleComputer::invalidate_rule_cache()
|
||||||
|
@ -2999,4 +3000,17 @@ size_t StyleComputer::number_of_css_font_faces_with_loading_in_progress() const
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StyleComputer::has_has_selectors() const
|
||||||
|
{
|
||||||
|
build_rule_cache_if_needed();
|
||||||
|
return m_selector_insights->has_has_selectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StyleComputer::has_attribute_selector(FlyString const& attribute_name) const
|
||||||
|
{
|
||||||
|
build_rule_cache_if_needed();
|
||||||
|
|
||||||
|
return m_selector_insights->all_names_used_in_attribute_selectors.contains(attribute_name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,8 @@ public:
|
||||||
};
|
};
|
||||||
void collect_animation_into(DOM::Element&, Optional<CSS::Selector::PseudoElement::Type>, GC::Ref<Animations::KeyframeEffect> animation, ComputedProperties&, AnimationRefresh = AnimationRefresh::No) const;
|
void collect_animation_into(DOM::Element&, Optional<CSS::Selector::PseudoElement::Type>, GC::Ref<Animations::KeyframeEffect> animation, ComputedProperties&, AnimationRefresh = AnimationRefresh::No) const;
|
||||||
|
|
||||||
[[nodiscard]] bool has_has_selectors() const { return m_has_has_selectors; }
|
[[nodiscard]] bool has_has_selectors() const;
|
||||||
|
[[nodiscard]] bool has_attribute_selector(FlyString const& attribute_name) const;
|
||||||
|
|
||||||
size_t number_of_css_font_faces_with_loading_in_progress() const;
|
size_t number_of_css_font_faces_with_loading_in_progress() const;
|
||||||
|
|
||||||
|
@ -247,6 +248,11 @@ private:
|
||||||
|
|
||||||
GC::Ref<DOM::Document> m_document;
|
GC::Ref<DOM::Document> m_document;
|
||||||
|
|
||||||
|
struct SelectorInsights {
|
||||||
|
bool has_has_selectors { false };
|
||||||
|
HashTable<FlyString> all_names_used_in_attribute_selectors;
|
||||||
|
};
|
||||||
|
|
||||||
struct RuleCache {
|
struct RuleCache {
|
||||||
HashMap<FlyString, Vector<MatchingRule>> rules_by_id;
|
HashMap<FlyString, Vector<MatchingRule>> rules_by_id;
|
||||||
HashMap<FlyString, Vector<MatchingRule>> rules_by_class;
|
HashMap<FlyString, Vector<MatchingRule>> rules_by_class;
|
||||||
|
@ -257,15 +263,15 @@ private:
|
||||||
Vector<MatchingRule> other_rules;
|
Vector<MatchingRule> other_rules;
|
||||||
|
|
||||||
HashMap<FlyString, NonnullRefPtr<Animations::KeyframeEffect::KeyFrameSet>> rules_by_animation_keyframes;
|
HashMap<FlyString, NonnullRefPtr<Animations::KeyframeEffect::KeyFrameSet>> rules_by_animation_keyframes;
|
||||||
|
|
||||||
bool has_has_selectors { false };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NonnullOwnPtr<RuleCache> make_rule_cache_for_cascade_origin(CascadeOrigin);
|
NonnullOwnPtr<RuleCache> make_rule_cache_for_cascade_origin(CascadeOrigin, SelectorInsights&);
|
||||||
|
|
||||||
RuleCache const& rule_cache_for_cascade_origin(CascadeOrigin) const;
|
RuleCache const& rule_cache_for_cascade_origin(CascadeOrigin) const;
|
||||||
|
|
||||||
bool m_has_has_selectors { false };
|
static void collect_selector_insights(Selector const&, SelectorInsights&);
|
||||||
|
|
||||||
|
OwnPtr<SelectorInsights> m_selector_insights;
|
||||||
OwnPtr<RuleCache> m_author_rule_cache;
|
OwnPtr<RuleCache> m_author_rule_cache;
|
||||||
OwnPtr<RuleCache> m_user_rule_cache;
|
OwnPtr<RuleCache> m_user_rule_cache;
|
||||||
OwnPtr<RuleCache> m_user_agent_rule_cache;
|
OwnPtr<RuleCache> m_user_agent_rule_cache;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue