LibWeb: Speed up CSS namespace checking
CSSStyleSheet now caches the CSSNamespaceRule for the default namespace, which is the only one we currently care about. This saves us from iterating over its list of rules every time we want to know what that default namespace is. The spec dictates that `@namespace` rules are only valid near the start of a stylesheet, so we also take advantage of that to quit searching for namespaces as soon as we see a non-import rule. Also renamed `namespace_filter()` to `default_namespace()` since that's what it actually returns. This makes github.com/serenityos/serenity snappy again. :^)
This commit is contained in:
parent
496db17c2d
commit
0805060e5e
Notes:
sideshowbarker
2024-07-16 22:22:13 +09:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/SerenityOS/serenity/commit/0805060e5e Pull-request: https://github.com/SerenityOS/serenity/pull/20283 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/stelar7
3 changed files with 43 additions and 11 deletions
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <LibWeb/Bindings/CSSStyleSheetPrototype.h>
|
#include <LibWeb/Bindings/CSSStyleSheetPrototype.h>
|
||||||
#include <LibWeb/Bindings/Intrinsics.h>
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
#include <LibWeb/CSS/CSSNamespaceRule.h>
|
|
||||||
#include <LibWeb/CSS/CSSStyleSheet.h>
|
#include <LibWeb/CSS/CSSStyleSheet.h>
|
||||||
#include <LibWeb/CSS/Parser/Parser.h>
|
#include <LibWeb/CSS/Parser/Parser.h>
|
||||||
#include <LibWeb/CSS/StyleComputer.h>
|
#include <LibWeb/CSS/StyleComputer.h>
|
||||||
|
@ -30,6 +29,12 @@ CSSStyleSheet::CSSStyleSheet(JS::Realm& realm, CSSRuleList& rules, MediaList& me
|
||||||
|
|
||||||
for (auto& rule : *m_rules)
|
for (auto& rule : *m_rules)
|
||||||
rule->set_parent_style_sheet(this);
|
rule->set_parent_style_sheet(this);
|
||||||
|
|
||||||
|
recalculate_namespaces();
|
||||||
|
|
||||||
|
m_rules->on_change = [this]() {
|
||||||
|
recalculate_namespaces();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::ThrowCompletionOr<void> CSSStyleSheet::initialize(JS::Realm& realm)
|
JS::ThrowCompletionOr<void> CSSStyleSheet::initialize(JS::Realm& realm)
|
||||||
|
@ -138,17 +143,40 @@ void CSSStyleSheet::set_style_sheet_list(Badge<StyleSheetList>, StyleSheetList*
|
||||||
m_style_sheet_list = list;
|
m_style_sheet_list = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<StringView> CSSStyleSheet::namespace_filter() const
|
Optional<StringView> CSSStyleSheet::default_namespace() const
|
||||||
{
|
{
|
||||||
for (JS::NonnullGCPtr<CSSRule> rule : *m_rules) {
|
if (m_default_namespace_rule)
|
||||||
if (rule->type() == CSSRule::Type::Namespace) {
|
return m_default_namespace_rule->namespace_uri().view();
|
||||||
auto& namespace_rule = verify_cast<CSSNamespaceRule>(*rule);
|
|
||||||
if (!namespace_rule.namespace_uri().is_empty() && namespace_rule.prefix().is_empty())
|
|
||||||
return namespace_rule.namespace_uri().view();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSSStyleSheet::recalculate_namespaces()
|
||||||
|
{
|
||||||
|
for (JS::NonnullGCPtr<CSSRule> rule : *m_rules) {
|
||||||
|
// "Any @namespace rules must follow all @charset and @import rules and precede all other
|
||||||
|
// non-ignored at-rules and style rules in a style sheet.
|
||||||
|
// ...
|
||||||
|
// A syntactically invalid @namespace rule (whether malformed or misplaced) must be ignored."
|
||||||
|
// https://drafts.csswg.org/css-namespaces/#syntax
|
||||||
|
switch (rule->type()) {
|
||||||
|
case CSSRule::Type::Import:
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case CSSRule::Type::Namespace:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Any other types mean that further @namespace rules are invalid, so we can stop here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& namespace_rule = verify_cast<CSSNamespaceRule>(*rule);
|
||||||
|
if (!namespace_rule.namespace_uri().is_empty() && namespace_rule.prefix().is_empty())
|
||||||
|
m_default_namespace_rule = namespace_rule;
|
||||||
|
|
||||||
|
// FIXME: Store qualified namespace rules.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
|
#include <LibWeb/CSS/CSSNamespaceRule.h>
|
||||||
#include <LibWeb/CSS/CSSRule.h>
|
#include <LibWeb/CSS/CSSRule.h>
|
||||||
#include <LibWeb/CSS/CSSRuleList.h>
|
#include <LibWeb/CSS/CSSRuleList.h>
|
||||||
#include <LibWeb/CSS/CSSStyleRule.h>
|
#include <LibWeb/CSS/CSSStyleRule.h>
|
||||||
|
@ -48,7 +49,7 @@ public:
|
||||||
|
|
||||||
void set_style_sheet_list(Badge<StyleSheetList>, StyleSheetList*);
|
void set_style_sheet_list(Badge<StyleSheetList>, StyleSheetList*);
|
||||||
|
|
||||||
Optional<StringView> namespace_filter() const;
|
Optional<StringView> default_namespace() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSSStyleSheet(JS::Realm&, CSSRuleList&, MediaList&, Optional<AK::URL> location);
|
CSSStyleSheet(JS::Realm&, CSSRuleList&, MediaList&, Optional<AK::URL> location);
|
||||||
|
@ -56,7 +57,10 @@ private:
|
||||||
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
|
void recalculate_namespaces();
|
||||||
|
|
||||||
JS::GCPtr<CSSRuleList> m_rules;
|
JS::GCPtr<CSSRuleList> m_rules;
|
||||||
|
JS::GCPtr<CSSNamespaceRule> m_default_namespace_rule;
|
||||||
|
|
||||||
JS::GCPtr<StyleSheetList> m_style_sheet_list;
|
JS::GCPtr<StyleSheetList> m_style_sheet_list;
|
||||||
JS::GCPtr<CSSRule> m_owner_css_rule;
|
JS::GCPtr<CSSRule> m_owner_css_rule;
|
||||||
|
|
|
@ -225,7 +225,7 @@ Vector<MatchingRule> StyleComputer::filter_namespace_rules(DOM::Element const& e
|
||||||
Vector<MatchingRule> filtered_rules;
|
Vector<MatchingRule> filtered_rules;
|
||||||
|
|
||||||
for (auto const& rule : rules) {
|
for (auto const& rule : rules) {
|
||||||
auto namespace_uri = rule.sheet->namespace_filter();
|
auto namespace_uri = rule.sheet->default_namespace();
|
||||||
if (namespace_uri.has_value()) {
|
if (namespace_uri.has_value()) {
|
||||||
if (namespace_uri.value() == element.namespace_uri())
|
if (namespace_uri.value() == element.namespace_uri())
|
||||||
filtered_rules.append(rule);
|
filtered_rules.append(rule);
|
||||||
|
|
Loading…
Add table
Reference in a new issue