From 0805060e5ef5366f7e2f8454a69086b0ff451acb Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 31 Jul 2023 17:46:57 +0100 Subject: [PATCH] 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. :^) --- .../Libraries/LibWeb/CSS/CSSStyleSheet.cpp | 46 +++++++++++++++---- Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h | 6 ++- .../Libraries/LibWeb/CSS/StyleComputer.cpp | 2 +- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp index d3a29d41f9..b2055922d9 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -30,6 +29,12 @@ CSSStyleSheet::CSSStyleSheet(JS::Realm& realm, CSSRuleList& rules, MediaList& me for (auto& rule : *m_rules) rule->set_parent_style_sheet(this); + + recalculate_namespaces(); + + m_rules->on_change = [this]() { + recalculate_namespaces(); + }; } JS::ThrowCompletionOr CSSStyleSheet::initialize(JS::Realm& realm) @@ -138,17 +143,40 @@ void CSSStyleSheet::set_style_sheet_list(Badge, StyleSheetList* m_style_sheet_list = list; } -Optional CSSStyleSheet::namespace_filter() const +Optional CSSStyleSheet::default_namespace() const { - for (JS::NonnullGCPtr rule : *m_rules) { - if (rule->type() == CSSRule::Type::Namespace) { - auto& namespace_rule = verify_cast(*rule); - if (!namespace_rule.namespace_uri().is_empty() && namespace_rule.prefix().is_empty()) - return namespace_rule.namespace_uri().view(); - } - } + if (m_default_namespace_rule) + return m_default_namespace_rule->namespace_uri().view(); return {}; } +void CSSStyleSheet::recalculate_namespaces() +{ + for (JS::NonnullGCPtr 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(*rule); + if (!namespace_rule.namespace_uri().is_empty() && namespace_rule.prefix().is_empty()) + m_default_namespace_rule = namespace_rule; + + // FIXME: Store qualified namespace rules. + } +} + } diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h index c6d031f71e..cffc45f0b8 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -48,7 +49,7 @@ public: void set_style_sheet_list(Badge, StyleSheetList*); - Optional namespace_filter() const; + Optional default_namespace() const; private: CSSStyleSheet(JS::Realm&, CSSRuleList&, MediaList&, Optional location); @@ -56,7 +57,10 @@ private: virtual JS::ThrowCompletionOr initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; + void recalculate_namespaces(); + JS::GCPtr m_rules; + JS::GCPtr m_default_namespace_rule; JS::GCPtr m_style_sheet_list; JS::GCPtr m_owner_css_rule; diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index e951d292f4..221c363a2d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -225,7 +225,7 @@ Vector StyleComputer::filter_namespace_rules(DOM::Element const& e Vector filtered_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.value() == element.namespace_uri()) filtered_rules.append(rule);