LibWeb: Only invalidate shadow root when style sheet inside changes

We don't have to invalidate style for the entire document when a style
sheet changes inside of a shadow root.

To make this possible, StyleSheetList now keeps track of which
Document-or-ShadowRoot it corresponds to, instead of just tracking the
containing Document.

This avoids a lot of style recomputation on pages with lots of shadow
DOM content (like GitHub).
This commit is contained in:
Andreas Kling 2024-08-20 14:55:28 +02:00 committed by Andreas Kling
parent e71ed67069
commit 4bc3055c0f
Notes: github-actions[bot] 2024-08-20 14:11:28 +00:00
5 changed files with 37 additions and 25 deletions

View file

@ -108,9 +108,8 @@ void CSSStyleRule::set_selector_text(StringView selector_text)
m_selectors = parsed_selectors.release_value();
if (auto* sheet = parent_style_sheet()) {
if (auto style_sheet_list = sheet->style_sheet_list()) {
auto& document = style_sheet_list->document();
document.style_computer().invalidate_rule_cache();
document.invalidate_style();
style_sheet_list->document().style_computer().invalidate_rule_cache();
style_sheet_list->document_or_shadow_root().invalidate_style();
}
}
}

View file

@ -155,7 +155,7 @@ WebIDL::ExceptionOr<unsigned> CSSStyleSheet::insert_rule(StringView rule, unsign
if (m_style_sheet_list) {
m_style_sheet_list->document().style_computer().invalidate_rule_cache();
m_style_sheet_list->document().invalidate_style();
m_style_sheet_list->document_or_shadow_root().invalidate_style();
}
}
@ -176,7 +176,7 @@ WebIDL::ExceptionOr<void> CSSStyleSheet::delete_rule(unsigned index)
if (!result.is_exception()) {
if (m_style_sheet_list) {
m_style_sheet_list->document().style_computer().invalidate_rule_cache();
m_style_sheet_list->document().invalidate_style();
m_style_sheet_list->document_or_shadow_root().invalidate_style();
}
}
return result;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -107,9 +107,9 @@ void StyleSheetList::add_sheet(CSSStyleSheet& sheet)
return;
}
m_document->style_computer().invalidate_rule_cache();
m_document->style_computer().load_fonts_from_sheet(sheet);
m_document->invalidate_style();
document().style_computer().invalidate_rule_cache();
document().style_computer().load_fonts_from_sheet(sheet);
document_or_shadow_root().invalidate_style();
}
void StyleSheetList::remove_sheet(CSSStyleSheet& sheet)
@ -123,19 +123,19 @@ void StyleSheetList::remove_sheet(CSSStyleSheet& sheet)
return;
}
m_document->style_computer().invalidate_rule_cache();
m_document->invalidate_style();
m_document_or_shadow_root->document().style_computer().invalidate_rule_cache();
document_or_shadow_root().invalidate_style();
}
JS::NonnullGCPtr<StyleSheetList> StyleSheetList::create(DOM::Document& document)
JS::NonnullGCPtr<StyleSheetList> StyleSheetList::create(JS::NonnullGCPtr<DOM::Node> document_or_shadow_root)
{
auto& realm = document.realm();
return realm.heap().allocate<StyleSheetList>(realm, document);
auto& realm = document_or_shadow_root->realm();
return realm.heap().allocate<StyleSheetList>(realm, document_or_shadow_root);
}
StyleSheetList::StyleSheetList(DOM::Document& document)
: Bindings::PlatformObject(document.realm())
, m_document(document)
StyleSheetList::StyleSheetList(JS::NonnullGCPtr<DOM::Node> document_or_shadow_root)
: Bindings::PlatformObject(document_or_shadow_root->realm())
, m_document_or_shadow_root(document_or_shadow_root)
{
m_legacy_platform_object_flags = LegacyPlatformObjectFlags { .supports_indexed_properties = true };
}
@ -149,7 +149,7 @@ void StyleSheetList::initialize(JS::Realm& realm)
void StyleSheetList::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_document);
visitor.visit(m_document_or_shadow_root);
visitor.visit(m_sheets);
}
@ -161,4 +161,14 @@ Optional<JS::Value> StyleSheetList::item_value(size_t index) const
return m_sheets[index].ptr();
}
DOM::Document& StyleSheetList::document()
{
return m_document_or_shadow_root->document();
}
DOM::Document const& StyleSheetList::document() const
{
return m_document_or_shadow_root->document();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -17,7 +17,7 @@ class StyleSheetList final : public Bindings::PlatformObject {
JS_DECLARE_ALLOCATOR(StyleSheetList);
public:
[[nodiscard]] static JS::NonnullGCPtr<StyleSheetList> create(DOM::Document&);
[[nodiscard]] static JS::NonnullGCPtr<StyleSheetList> create(JS::NonnullGCPtr<DOM::Node> document_or_shadow_root);
void add_a_css_style_sheet(CSS::CSSStyleSheet&);
void remove_a_css_style_sheet(CSS::CSSStyleSheet&);
@ -37,11 +37,14 @@ public:
virtual Optional<JS::Value> item_value(size_t index) const override;
DOM::Document& document() { return m_document; }
DOM::Document const& document() const { return m_document; }
[[nodiscard]] DOM::Document& document();
[[nodiscard]] DOM::Document const& document() const;
[[nodiscard]] DOM::Node& document_or_shadow_root() { return m_document_or_shadow_root; }
[[nodiscard]] DOM::Node const& document_or_shadow_root() const { return m_document_or_shadow_root; }
private:
explicit StyleSheetList(DOM::Document&);
explicit StyleSheetList(JS::NonnullGCPtr<DOM::Node> document_or_shadow_root);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
@ -49,7 +52,7 @@ private:
void add_sheet(CSSStyleSheet&);
void remove_sheet(CSSStyleSheet&);
JS::NonnullGCPtr<DOM::Document> m_document;
JS::NonnullGCPtr<DOM::Node> m_document_or_shadow_root;
Vector<JS::NonnullGCPtr<CSSStyleSheet>> m_sheets;
// https://www.w3.org/TR/cssom/#preferred-css-style-sheet-set-name

View file

@ -122,7 +122,7 @@ WebIDL::ExceptionOr<void> ShadowRoot::set_html_unsafe(StringView html)
CSS::StyleSheetList& ShadowRoot::style_sheets()
{
if (!m_style_sheets)
m_style_sheets = CSS::StyleSheetList::create(document());
m_style_sheets = CSS::StyleSheetList::create(*this);
return *m_style_sheets;
}