diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index 01b7ef357cf..ff3c6e010f7 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -1063,12 +1063,12 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ return Ladybird::ns_rect_to_gfx_rect([[self window] frame]); }; - m_web_view_bridge->on_received_source = [weak_self](auto const& url, auto const& source) { + m_web_view_bridge->on_received_source = [weak_self](auto const& url, auto const& base_url, auto const& source) { LadybirdWebView* self = weak_self; if (self == nil) { return; } - auto html = WebView::highlight_source(MUST(url.to_string()), source, Syntax::Language::HTML, WebView::HighlightOutputMode::FullDocument); + auto html = WebView::highlight_source(url, base_url, source, Syntax::Language::HTML, WebView::HighlightOutputMode::FullDocument); [self.observer onCreateNewTab:html url:url diff --git a/Ladybird/Qt/Tab.cpp b/Ladybird/Qt/Tab.cpp index 8137c098810..129da7d8d96 100644 --- a/Ladybird/Qt/Tab.cpp +++ b/Ladybird/Qt/Tab.cpp @@ -321,8 +321,8 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St QObject::connect(focus_location_editor_action, &QAction::triggered, this, &Tab::focus_location_editor); - view().on_received_source = [this](auto const& url, auto const& source) { - auto html = WebView::highlight_source(MUST(url.to_string()), source, Syntax::Language::HTML, WebView::HighlightOutputMode::FullDocument); + view().on_received_source = [this](auto const& url, auto const& base_url, auto const& source) { + auto html = WebView::highlight_source(url, base_url, source, Syntax::Language::HTML, WebView::HighlightOutputMode::FullDocument); m_window->new_tab_from_content(html, Web::HTML::ActivateTab::Yes); }; diff --git a/Userland/Applications/Browser/Tab.cpp b/Userland/Applications/Browser/Tab.cpp index 9183f67c100..de52b12e9bc 100644 --- a/Userland/Applications/Browser/Tab.cpp +++ b/Userland/Applications/Browser/Tab.cpp @@ -69,7 +69,7 @@ void Tab::start_download(const URL::URL& url) window->show(); } -void Tab::view_source(const URL::URL& url, ByteString const& source) +void Tab::view_source(const URL::URL& url, StringView source) { auto window = GUI::Window::construct(&this->window()); auto editor = window->set_main_widget(); @@ -657,7 +657,9 @@ Tab::Tab(BrowserWindow& window) m_select_dropdown->popup(view().screen_relative_rect().location().translated(content_position)); }; - view().on_received_source = [this](auto& url, auto& source) { + view().on_received_source = [this](auto& url, auto const& base_url, auto const& source) { + // FIXME: Use base_url? + (void)base_url; view_source(url, source); }; diff --git a/Userland/Applications/Browser/Tab.h b/Userland/Applications/Browser/Tab.h index 9726f1a279e..b73c4885134 100644 --- a/Userland/Applications/Browser/Tab.h +++ b/Userland/Applications/Browser/Tab.h @@ -99,7 +99,7 @@ private: ErrorOr bookmark_current_url(); void update_bookmark_button(StringView url); void start_download(const URL::URL& url); - void view_source(const URL::URL& url, ByteString const& source); + void view_source(const URL::URL& url, StringView source); void update_status(Optional text_override = {}, i32 count_waiting = 0); void close_sub_widgets(); diff --git a/Userland/Libraries/LibWebView/InspectorClient.cpp b/Userland/Libraries/LibWebView/InspectorClient.cpp index f70b581a9e1..1eedbda3312 100644 --- a/Userland/Libraries/LibWebView/InspectorClient.cpp +++ b/Userland/Libraries/LibWebView/InspectorClient.cpp @@ -124,8 +124,8 @@ InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImple m_inspector_web_view.run_javascript(builder.string_view()); }; - m_content_web_view.on_received_style_sheet_source = [this](Web::CSS::StyleSheetIdentifier const& identifier, String const& source) { - auto html = highlight_source(identifier.url.value_or({}), source, Syntax::Language::CSS, HighlightOutputMode::SourceOnly); + m_content_web_view.on_received_style_sheet_source = [this](Web::CSS::StyleSheetIdentifier const& identifier, auto const& base_url, String const& source) { + auto html = highlight_source(identifier.url.value_or({}), base_url, source, Syntax::Language::CSS, HighlightOutputMode::SourceOnly); auto script = MUST(String::formatted("inspector.setStyleSheetSource({}, \"{}\");", style_sheet_identifier_to_json(identifier), MUST(encode_base64(html.bytes())))); diff --git a/Userland/Libraries/LibWebView/SourceHighlighter.cpp b/Userland/Libraries/LibWebView/SourceHighlighter.cpp index fe1a0588d49..f4ab5b5f96f 100644 --- a/Userland/Libraries/LibWebView/SourceHighlighter.cpp +++ b/Userland/Libraries/LibWebView/SourceHighlighter.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -113,10 +114,10 @@ void SourceHighlighterClient::highlighter_did_set_folding_regions(Vector )~~~"sv); - builder.appendff("View Source - {}", escape_html_entities(url)); + builder.appendff("View Source - {}", escape_html_entities(url.serialize_for_display())); builder.appendff("", HTML_HIGHLIGHTER_STYLE); builder.append(R"~~~( @@ -274,6 +275,22 @@ String SourceHighlighterClient::to_html_string(String const& url, HighlightOutpu } builder.append("
"sv);
 
+    static constexpr auto href = to_array({ 'h', 'r', 'e', 'f' });
+    static constexpr auto src = to_array({ 's', 'r', 'c' });
+    bool linkify_attribute = false;
+
+    auto resolve_url_for_attribute = [&](Utf32View const& attribute_value) -> Optional {
+        if (!linkify_attribute)
+            return {};
+
+        auto attribute_url = MUST(String::formatted("{}", attribute_value));
+        auto attribute_url_without_quotes = attribute_url.bytes_as_string_view().trim("\""sv);
+
+        if (auto resolved = Web::DOMURL::parse(attribute_url_without_quotes, base_url); resolved.is_valid())
+            return resolved;
+        return {};
+    };
+
     size_t span_index = 0;
     for (size_t line_index = 0; line_index < document().line_count(); ++line_index) {
         auto& line = document().line(line_index);
@@ -286,11 +303,27 @@ String SourceHighlighterClient::to_html_string(String const& url, HighlightOutpu
             size_t length = end - start;
             if (length == 0)
                 return;
+
             auto text = line_view.substring_view(start, length);
+
             if (span.has_value()) {
+                bool append_anchor_close = false;
+
+                if (span->data == to_underlying(Web::HTML::AugmentedTokenKind::AttributeName)) {
+                    linkify_attribute = text == Utf32View { href } || text == Utf32View { src };
+                } else if (span->data == to_underlying(Web::HTML::AugmentedTokenKind::AttributeValue)) {
+                    if (auto href = resolve_url_for_attribute(text); href.has_value()) {
+                        builder.appendff("", *href);
+                        append_anchor_close = true;
+                    }
+                }
+
                 start_token(span->data);
                 append_escaped(text);
                 end_token();
+
+                if (append_anchor_close)
+                    builder.append(""sv);
             } else {
                 append_escaped(text);
             }
diff --git a/Userland/Libraries/LibWebView/SourceHighlighter.h b/Userland/Libraries/LibWebView/SourceHighlighter.h
index f5a243e424f..8b938075e1b 100644
--- a/Userland/Libraries/LibWebView/SourceHighlighter.h
+++ b/Userland/Libraries/LibWebView/SourceHighlighter.h
@@ -7,11 +7,13 @@
 
 #pragma once
 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
 
 namespace WebView {
 
@@ -50,7 +52,7 @@ public:
     SourceHighlighterClient(StringView source, Syntax::Language);
     virtual ~SourceHighlighterClient() = default;
 
-    String to_html_string(String const&, HighlightOutputMode) const;
+    String to_html_string(URL::URL const& url, URL::URL const& base_url, HighlightOutputMode) const;
 
 private:
     // ^ Syntax::HighlighterClient
@@ -73,7 +75,7 @@ private:
     OwnPtr m_highlighter;
 };
 
-String highlight_source(String const&, StringView, Syntax::Language, HighlightOutputMode);
+String highlight_source(URL::URL const& url, URL::URL const& base_url, StringView, Syntax::Language, HighlightOutputMode);
 
 constexpr inline StringView HTML_HIGHLIGHTER_STYLE = R"~~~(
     @media (prefers-color-scheme: dark) {
diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h
index 9bf45e9a2bf..0302a02c7d8 100644
--- a/Userland/Libraries/LibWebView/ViewImplementation.h
+++ b/Userland/Libraries/LibWebView/ViewImplementation.h
@@ -180,13 +180,13 @@ public:
     Function on_request_set_prompt_text;
     Function on_request_accept_dialog;
     Function on_request_dismiss_dialog;
-    Function on_received_source;
+    Function on_received_source;
     Function on_received_dom_tree;
     Function)> on_received_dom_node_properties;
     Function on_received_accessibility_tree;
     Function)> on_received_style_sheet_list;
     Function on_inspector_requested_style_sheet_source;
-    Function on_received_style_sheet_source;
+    Function on_received_style_sheet_source;
     Function on_received_hovered_node_id;
     Function const& node_id)> on_finshed_editing_dom_node;
     Function on_received_dom_node_html;
diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp
index bbd6fc2d24a..3751e231c6b 100644
--- a/Userland/Libraries/LibWebView/WebContentClient.cpp
+++ b/Userland/Libraries/LibWebView/WebContentClient.cpp
@@ -253,11 +253,11 @@ void WebContentClient::did_request_media_context_menu(u64 page_id, Gfx::IntPoint
     }
 }
 
-void WebContentClient::did_get_source(u64 page_id, URL::URL const& url, ByteString const& source)
+void WebContentClient::did_get_source(u64 page_id, URL::URL const& url, URL::URL const& base_url, String const& source)
 {
     if (auto view = view_for_page_id(page_id); view.has_value()) {
         if (view->on_received_source)
-            view->on_received_source(url, source);
+            view->on_received_source(url, base_url, source);
     }
 }
 
@@ -714,11 +714,11 @@ void WebContentClient::inspector_did_request_style_sheet_source(u64 page_id, Web
     }
 }
 
-void WebContentClient::did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier const& identifier, String const& source)
+void WebContentClient::did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier const& identifier, URL::URL const& base_url, String const& source)
 {
     if (auto view = view_for_page_id(page_id); view.has_value()) {
         if (view->on_received_style_sheet_source)
-            view->on_received_style_sheet_source(identifier, source);
+            view->on_received_style_sheet_source(identifier, base_url, source);
     }
 }
 
diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h
index 58b7dc2f8a0..9551c33ec71 100644
--- a/Userland/Libraries/LibWebView/WebContentClient.h
+++ b/Userland/Libraries/LibWebView/WebContentClient.h
@@ -61,7 +61,7 @@ private:
     virtual void did_request_link_context_menu(u64 page_id, Gfx::IntPoint, URL::URL const&, ByteString const&, unsigned) override;
     virtual void did_request_image_context_menu(u64 page_id, Gfx::IntPoint, URL::URL const&, ByteString const&, unsigned, Gfx::ShareableBitmap const&) override;
     virtual void did_request_media_context_menu(u64 page_id, Gfx::IntPoint, ByteString const&, unsigned, Web::Page::MediaContextMenu const&) override;
-    virtual void did_get_source(u64 page_id, URL::URL const&, ByteString const&) override;
+    virtual void did_get_source(u64 page_id, URL::URL const&, URL::URL const&, String const&) override;
     virtual void did_inspect_dom_tree(u64 page_id, ByteString const&) override;
     virtual void did_inspect_dom_node(u64 page_id, bool has_style, ByteString const& computed_style, ByteString const& resolved_style, ByteString const& custom_properties, ByteString const& node_box_sizing, ByteString const& aria_properties_state, ByteString const& fonts) override;
     virtual void did_inspect_accessibility_tree(u64 page_id, ByteString const&) override;
@@ -117,7 +117,7 @@ private:
     virtual Messages::WebContentClient::RequestWorkerAgentResponse request_worker_agent(u64 page_id) override;
     virtual void inspector_did_list_style_sheets(u64 page_id, Vector const& stylesheets) override;
     virtual void inspector_did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier const& identifier) override;
-    virtual void did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier const& identifier, String const& source) override;
+    virtual void did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier const& identifier, URL::URL const&, String const& source) override;
 
     Optional view_for_page_id(u64, SourceLocation = SourceLocation::current());
 
diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp
index 81174295086..f273d514fe3 100644
--- a/Userland/Services/WebContent/ConnectionFromClient.cpp
+++ b/Userland/Services/WebContent/ConnectionFromClient.cpp
@@ -460,7 +460,7 @@ void ConnectionFromClient::get_source(u64 page_id)
 {
     if (auto page = this->page(page_id); page.has_value()) {
         if (auto* doc = page->page().top_level_browsing_context().active_document())
-            async_did_get_source(page_id, doc->url(), doc->source().to_byte_string());
+            async_did_get_source(page_id, doc->url(), doc->base_url(), doc->source());
     }
 }
 
@@ -673,9 +673,8 @@ void ConnectionFromClient::request_style_sheet_source(u64 page_id, Web::CSS::Sty
         return;
 
     if (auto* document = page->page().top_level_browsing_context().active_document()) {
-        auto stylesheet = document->get_style_sheet_source(identifier);
-        if (stylesheet.has_value())
-            async_did_request_style_sheet_source(page_id, identifier, stylesheet.value());
+        if (auto stylesheet = document->get_style_sheet_source(identifier); stylesheet.has_value())
+            async_did_get_style_sheet_source(page_id, identifier, document->base_url(), stylesheet.value());
     }
 }
 
diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc
index d8b785434a5..cd7724b2bcb 100644
--- a/Userland/Services/WebContent/WebContentClient.ipc
+++ b/Userland/Services/WebContent/WebContentClient.ipc
@@ -50,7 +50,7 @@ endpoint WebContentClient
     did_request_set_prompt_text(u64 page_id, String message) =|
     did_request_accept_dialog(u64 page_id) =|
     did_request_dismiss_dialog(u64 page_id) =|
-    did_get_source(u64 page_id, URL::URL url, ByteString source) =|
+    did_get_source(u64 page_id, URL::URL url, URL::URL base_url, String source) =|
 
     did_inspect_dom_tree(u64 page_id, ByteString dom_tree) =|
     did_inspect_dom_node(u64 page_id, bool has_style, ByteString computed_style,  ByteString resolved_style,  ByteString custom_properties, ByteString node_box_sizing, ByteString aria_properties_state, ByteString fonts) =|
@@ -61,7 +61,7 @@ endpoint WebContentClient
 
     inspector_did_list_style_sheets(u64 page_id, Vector style_sheets) =|
     inspector_did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) =|
-    did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, String source) =|
+    did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier, URL::URL base_url, String source) =|
 
     did_take_screenshot(u64 page_id, Gfx::ShareableBitmap screenshot) =|