From ba030f0363e1cc77a3244fe0134ff83ea521710c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 25 Mar 2025 10:04:42 +0000 Subject: [PATCH] LibWeb: Add an engine-internal CSS realm for internal style parsing This is used for default UA style right now, and we'll expand its use in the near future. Note that this required teaching the CSS parser to handle url() functions when there's no document URL to resolve them against. If we don't handle that, namespace rules in UA style don't parse correctly. --- Libraries/LibWeb/CSS/Parser/Helpers.cpp | 29 ++++++++++++++++++++++++- Libraries/LibWeb/CSS/Parser/Parser.cpp | 3 +++ Libraries/LibWeb/CSS/Parser/Parser.h | 1 + Libraries/LibWeb/CSS/StyleComputer.cpp | 24 ++++++++++---------- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/Libraries/LibWeb/CSS/Parser/Helpers.cpp b/Libraries/LibWeb/CSS/Parser/Helpers.cpp index 52f7cb22d73..c24ecf70bba 100644 --- a/Libraries/LibWeb/CSS/Parser/Helpers.cpp +++ b/Libraries/LibWeb/CSS/Parser/Helpers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2022, Andreas Kling + * Copyright (c) 2018-2025, Andreas Kling * Copyright (c) 2020-2023, the SerenityOS developers. * Copyright (c) 2021-2024, Sam Atkins * Copyright (c) 2021, Tobias Christiansen @@ -8,13 +8,40 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include #include #include #include +#include namespace Web { +GC::Ref internal_css_realm() +{ + static GC::Root realm; + static GC::Root window; + static OwnPtr execution_context; + if (!realm) { + execution_context = Bindings::create_a_new_javascript_realm( + Bindings::main_thread_vm(), + [&](JS::Realm& realm) -> JS::Object* { + window = HTML::Window::create(realm); + return window; + }, + [&](JS::Realm&) -> JS::Object* { + return window; + }); + + realm = *execution_context->realm; + auto intrinsics = realm->create(*realm); + auto host_defined = make(intrinsics); + realm->set_host_defined(move(host_defined)); + } + return *realm; +} + CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& context, StringView css, Optional location) { if (css.is_empty()) { diff --git a/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Libraries/LibWeb/CSS/Parser/Parser.cpp index f01ec0aa5ff..a5a6d121204 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -1814,6 +1815,8 @@ bool Parser::is_parsing_svg_presentation_attribute() const // FIXME: URLs shouldn't be completed during parsing, but when used. Optional Parser::complete_url(StringView relative_url) const { + if (!m_url.is_valid()) + return URL::Parser::basic_parse(relative_url); return m_url.complete_url(relative_url); } diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index 468f2ca0ad8..208a01da7f3 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -521,5 +521,6 @@ CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingParams const&, StringView); RefPtr parse_media_query(CSS::Parser::ParsingParams const&, StringView); Vector> parse_media_query_list(CSS::Parser::ParsingParams const&, StringView); RefPtr parse_css_supports(CSS::Parser::ParsingParams const&, StringView); +GC::Ref internal_css_realm(); } diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 41f5d189615..c8a8426f975 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -309,42 +309,42 @@ struct StyleComputer::MatchingFontCandidate { } }; -static CSSStyleSheet& default_stylesheet(DOM::Document const& document) +static CSSStyleSheet& default_stylesheet() { static GC::Root sheet; if (!sheet.cell()) { extern String default_stylesheet_source; - sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(document), default_stylesheet_source)); + sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm()), default_stylesheet_source)); } return *sheet; } -static CSSStyleSheet& quirks_mode_stylesheet(DOM::Document const& document) +static CSSStyleSheet& quirks_mode_stylesheet() { static GC::Root sheet; if (!sheet.cell()) { extern String quirks_mode_stylesheet_source; - sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(document), quirks_mode_stylesheet_source)); + sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm()), quirks_mode_stylesheet_source)); } return *sheet; } -static CSSStyleSheet& mathml_stylesheet(DOM::Document const& document) +static CSSStyleSheet& mathml_stylesheet() { static GC::Root sheet; if (!sheet.cell()) { extern String mathml_stylesheet_source; - sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(document), mathml_stylesheet_source)); + sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm()), mathml_stylesheet_source)); } return *sheet; } -static CSSStyleSheet& svg_stylesheet(DOM::Document const& document) +static CSSStyleSheet& svg_stylesheet() { static GC::Root sheet; if (!sheet.cell()) { extern String svg_stylesheet_source; - sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(document), svg_stylesheet_source)); + sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm()), svg_stylesheet_source)); } return *sheet; } @@ -371,11 +371,11 @@ template void StyleComputer::for_each_stylesheet(CascadeOrigin cascade_origin, Callback callback) const { if (cascade_origin == CascadeOrigin::UserAgent) { - callback(default_stylesheet(document()), {}); + callback(default_stylesheet(), {}); if (document().in_quirks_mode()) - callback(quirks_mode_stylesheet(document()), {}); - callback(mathml_stylesheet(document()), {}); - callback(svg_stylesheet(document()), {}); + callback(quirks_mode_stylesheet(), {}); + callback(mathml_stylesheet(), {}); + callback(svg_stylesheet(), {}); } if (cascade_origin == CascadeOrigin::User) { if (m_user_style_sheet)