diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 7d899cf6d1..e68bfefee2 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -102,6 +102,7 @@ set(SOURCES CSS/StyleProperties.cpp CSS/StyleProperty.cpp CSS/StyleSheet.cpp + CSS/StyleSheetIdentifier.cpp CSS/StyleSheetList.cpp CSS/StyleValues/AngleStyleValue.cpp CSS/StyleValues/BackgroundRepeatStyleValue.cpp diff --git a/Userland/Libraries/LibWeb/CSS/StyleSheetIdentifier.cpp b/Userland/Libraries/LibWeb/CSS/StyleSheetIdentifier.cpp new file mode 100644 index 0000000000..2af12c9ccc --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleSheetIdentifier.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "StyleSheetIdentifier.h" +#include +#include + +namespace Web::CSS { + +StringView style_sheet_identifier_type_to_string(StyleSheetIdentifier::Type type) +{ + switch (type) { + case StyleSheetIdentifier::Type::StyleElement: + return "StyleElement"sv; + case StyleSheetIdentifier::Type::LinkElement: + return "LinkElement"sv; + case StyleSheetIdentifier::Type::ImportRule: + return "ImportRule"sv; + case StyleSheetIdentifier::Type::UserAgent: + return "UserAgent"sv; + case StyleSheetIdentifier::Type::UserStyle: + return "UserStyle"sv; + } + VERIFY_NOT_REACHED(); +} + +Optional style_sheet_identifier_type_from_string(StringView string) +{ + if (string == "StyleElement"sv) + return StyleSheetIdentifier::Type::StyleElement; + if (string == "LinkElement"sv) + return StyleSheetIdentifier::Type::LinkElement; + if (string == "ImportRule"sv) + return StyleSheetIdentifier::Type::ImportRule; + if (string == "UserAgent"sv) + return StyleSheetIdentifier::Type::UserAgent; + if (string == "UserStyle"sv) + return StyleSheetIdentifier::Type::UserStyle; + return {}; +} + +} + +namespace IPC { + +template<> +ErrorOr encode(Encoder& encoder, Web::CSS::StyleSheetIdentifier const& style_sheet_source) +{ + TRY(encoder.encode(style_sheet_source.type)); + TRY(encoder.encode(style_sheet_source.dom_element_unique_id)); + TRY(encoder.encode(style_sheet_source.url)); + + return {}; +} + +template<> +ErrorOr decode(Decoder& decoder) +{ + auto type = TRY(decoder.decode()); + auto dom_element_unique_id = TRY(decoder.decode>()); + auto url = TRY(decoder.decode>()); + + return Web::CSS::StyleSheetIdentifier { + .type = type, + .dom_element_unique_id = move(dom_element_unique_id), + .url = move(url), + }; +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleSheetIdentifier.h b/Userland/Libraries/LibWeb/CSS/StyleSheetIdentifier.h new file mode 100644 index 0000000000..82a6968bdb --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleSheetIdentifier.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::CSS { + +struct StyleSheetIdentifier { + enum class Type : u8 { + StyleElement, + LinkElement, + ImportRule, + UserAgent, + UserStyle, + } type; + Optional dom_element_unique_id {}; + Optional url {}; +}; + +StringView style_sheet_identifier_type_to_string(StyleSheetIdentifier::Type); +Optional style_sheet_identifier_type_from_string(StringView); +} + +namespace IPC { + +template<> +ErrorOr encode(Encoder&, Web::CSS::StyleSheetIdentifier const&); + +template<> +ErrorOr decode(Decoder&); + +} diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index a2e3da96d6..289731d2aa 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -83,6 +83,7 @@ public: virtual bool is_svg_element() const { return false; } virtual bool is_svg_graphics_element() const { return false; } virtual bool is_svg_script_element() const { return false; } + virtual bool is_svg_style_element() const { return false; } virtual bool is_svg_svg_element() const { return false; } virtual bool is_svg_use_element() const { return false; } @@ -100,8 +101,10 @@ public: virtual bool is_html_base_element() const { return false; } virtual bool is_html_body_element() const { return false; } virtual bool is_html_input_element() const { return false; } + virtual bool is_html_link_element() const { return false; } virtual bool is_html_progress_element() const { return false; } virtual bool is_html_script_element() const { return false; } + virtual bool is_html_style_element() const { return false; } virtual bool is_html_template_element() const { return false; } virtual bool is_html_table_element() const { return false; } virtual bool is_html_table_section_element() const { return false; } diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 90c2debc81..3362b24a85 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -200,6 +200,7 @@ class StringStyleValue; class StyleComputer; class StyleProperties; class StyleSheet; +struct StyleSheetIdentifier; class StyleSheetList; class StyleValueList; class Supports; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.h b/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.h index 4f572d1226..b2c50a1625 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.h @@ -53,7 +53,10 @@ private: virtual void resource_did_fail() override; virtual void resource_did_load() override; - // ^ HTMLElement + // ^DOM::Node + virtual bool is_html_link_element() const override { return true; } + + // ^HTMLElement virtual void visit_edges(Cell::Visitor&) override; struct LinkProcessingOptions { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLStyleElement.h b/Userland/Libraries/LibWeb/HTML/HTMLStyleElement.h index 86cb2c4ca1..51ce4e7f88 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLStyleElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLStyleElement.h @@ -32,6 +32,9 @@ public: private: HTMLStyleElement(DOM::Document&, DOM::QualifiedName); + // ^DOM::Node + virtual bool is_html_style_element() const override { return true; } + virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Userland/Libraries/LibWeb/SVG/SVGStyleElement.h b/Userland/Libraries/LibWeb/SVG/SVGStyleElement.h index a688b61314..7085571b25 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGStyleElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGStyleElement.h @@ -28,6 +28,9 @@ public: private: SVGStyleElement(DOM::Document&, DOM::QualifiedName); + // ^DOM::Node + virtual bool is_svg_style_element() const override { return true; } + virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index 00d40f6c8b..eff6e086c5 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -10,9 +10,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -739,6 +742,88 @@ void PageClient::did_get_js_console_messages(i32 start_index, Vector client().async_did_get_js_console_messages(m_id, start_index, move(message_types), move(messages)); } +static void gather_style_sheets(Vector& results, Web::CSS::CSSStyleSheet& sheet) +{ + Web::CSS::StyleSheetIdentifier identifier {}; + + bool valid = true; + + if (sheet.owner_rule()) { + identifier.type = Web::CSS::StyleSheetIdentifier::Type::ImportRule; + } else if (auto* node = sheet.owner_node()) { + if (node->is_html_style_element() || node->is_svg_style_element()) { + identifier.type = Web::CSS::StyleSheetIdentifier::Type::StyleElement; + } else if (is(node)) { + identifier.type = Web::CSS::StyleSheetIdentifier::Type::LinkElement; + } else { + dbgln("Can't identify where style sheet came from; owner node is {}", node->debug_description()); + identifier.type = Web::CSS::StyleSheetIdentifier::Type::StyleElement; + } + identifier.dom_element_unique_id = node->unique_id(); + } else { + dbgln("Style sheet has no owner rule or owner node; skipping"); + valid = false; + } + + if (valid) { + if (auto location = sheet.location(); location.has_value()) + identifier.url = location.release_value(); + + results.append(move(identifier)); + } + + for (auto& import_rule : sheet.import_rules()) { + if (import_rule->loaded_style_sheet()) { + gather_style_sheets(results, *import_rule->loaded_style_sheet()); + } else { + // We can gather this anyway, and hope it loads later + results.append({ .type = Web::CSS::StyleSheetIdentifier::Type::ImportRule, + .url = MUST(import_rule->url().to_string()) }); + } + } +} + +Vector PageClient::list_style_sheets() const +{ + Vector results; + + auto const* document = page().top_level_browsing_context().active_document(); + if (document) { + for (auto& sheet : document->style_sheets().sheets()) { + gather_style_sheets(results, sheet); + } + } + + // User style + if (page().user_style().has_value()) { + results.append({ + .type = Web::CSS::StyleSheetIdentifier::Type::UserStyle, + }); + } + + // User-agent + results.append({ + .type = Web::CSS::StyleSheetIdentifier::Type::UserAgent, + .url = "CSS/Default.css"_string, + }); + if (document && document->in_quirks_mode()) { + results.append({ + .type = Web::CSS::StyleSheetIdentifier::Type::UserAgent, + .url = "CSS/QuirksMode.css"_string, + }); + } + results.append({ + .type = Web::CSS::StyleSheetIdentifier::Type::UserAgent, + .url = "MathML/Default.css"_string, + }); + results.append({ + .type = Web::CSS::StyleSheetIdentifier::Type::UserAgent, + .url = "SVG/Default.css"_string, + }); + + return results; +} + Web::DisplayListPlayerType PageClient::display_list_player_type() const { switch (s_use_skia_painter) { diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h index 41d91138d1..b5799b350d 100644 --- a/Userland/Services/WebContent/PageClient.h +++ b/Userland/Services/WebContent/PageClient.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -83,6 +84,8 @@ public: void console_peer_did_misbehave(char const* reason); void did_get_js_console_messages(i32 start_index, Vector message_types, Vector messages); + Vector list_style_sheets() const; + virtual double device_pixels_per_css_pixel() const override { return m_device_pixels_per_css_pixel; } virtual Web::DisplayListPlayerType display_list_player_type() const override;