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.
This commit is contained in:
Andreas Kling 2025-03-25 10:04:42 +00:00 committed by Andreas Kling
parent c12f8b80dc
commit ba030f0363
Notes: github-actions[bot] 2025-03-25 23:58:04 +00:00
4 changed files with 44 additions and 13 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2018-2025, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2020-2023, the SerenityOS developers.
* Copyright (c) 2021-2024, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
@ -8,13 +8,40 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Bindings/PrincipalHostDefined.h>
#include <LibWeb/CSS/CSSMediaRule.h>
#include <LibWeb/CSS/CSSRuleList.h>
#include <LibWeb/CSS/CSSStyleSheet.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/HTML/Window.h>
namespace Web {
GC::Ref<JS::Realm> internal_css_realm()
{
static GC::Root<JS::Realm> realm;
static GC::Root<HTML::Window> window;
static OwnPtr<JS::ExecutionContext> 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<Bindings::Intrinsics>(*realm);
auto host_defined = make<Bindings::HostDefined>(intrinsics);
realm->set_host_defined(move(host_defined));
}
return *realm;
}
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& context, StringView css, Optional<URL::URL> location)
{
if (css.is_empty()) {

View file

@ -13,6 +13,7 @@
*/
#include <AK/Debug.h>
#include <LibURL/Parser.h>
#include <LibWeb/CSS/CSSStyleDeclaration.h>
#include <LibWeb/CSS/CSSStyleProperties.h>
#include <LibWeb/CSS/CSSStyleSheet.h>
@ -1814,6 +1815,8 @@ bool Parser::is_parsing_svg_presentation_attribute() const
// FIXME: URLs shouldn't be completed during parsing, but when used.
Optional<URL::URL> 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);
}

View file

@ -521,5 +521,6 @@ CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingParams const&, StringView);
RefPtr<CSS::MediaQuery> parse_media_query(CSS::Parser::ParsingParams const&, StringView);
Vector<NonnullRefPtr<CSS::MediaQuery>> parse_media_query_list(CSS::Parser::ParsingParams const&, StringView);
RefPtr<CSS::Supports> parse_css_supports(CSS::Parser::ParsingParams const&, StringView);
GC::Ref<JS::Realm> internal_css_realm();
}

View file

@ -309,42 +309,42 @@ struct StyleComputer::MatchingFontCandidate {
}
};
static CSSStyleSheet& default_stylesheet(DOM::Document const& document)
static CSSStyleSheet& default_stylesheet()
{
static GC::Root<CSSStyleSheet> 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<CSSStyleSheet> 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<CSSStyleSheet> 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<CSSStyleSheet> 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<typename Callback>
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)