diff --git a/Ladybird/WebContent/CMakeLists.txt b/Ladybird/WebContent/CMakeLists.txt index 72aad5417d..7fa8701ae7 100644 --- a/Ladybird/WebContent/CMakeLists.txt +++ b/Ladybird/WebContent/CMakeLists.txt @@ -4,6 +4,7 @@ set(WEBCONTENT_SOURCE_DIR ${SERENITY_SOURCE_DIR}/Userland/Services/WebContent/) set(WEBCONTENT_SOURCES ${WEBCONTENT_SOURCE_DIR}/ConnectionFromClient.cpp ${WEBCONTENT_SOURCE_DIR}/ConsoleGlobalEnvironmentExtensions.cpp + ${WEBCONTENT_SOURCE_DIR}/PageClient.cpp ${WEBCONTENT_SOURCE_DIR}/PageHost.cpp ${WEBCONTENT_SOURCE_DIR}/WebContentConsoleClient.cpp ${WEBCONTENT_SOURCE_DIR}/WebDriverConnection.cpp diff --git a/Ladybird/WebContent/main.cpp b/Ladybird/WebContent/main.cpp index 8d4d1bbac3..52cd886d9f 100644 --- a/Ladybird/WebContent/main.cpp +++ b/Ladybird/WebContent/main.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #if defined(HAVE_QT) @@ -87,7 +87,7 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.parse(arguments); if (use_gpu_painting) { - WebContent::PageHost::set_use_gpu_painter(); + WebContent::PageClient::set_use_gpu_painter(); } #if defined(HAVE_QT) diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index e9a0df831b..a7ebcb332f 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -26,7 +26,6 @@ namespace Web { Page::Page(PageClient& client) : m_client(client) { - m_top_level_traversable = JS::make_handle(HTML::TraversableNavigable::create_a_fresh_top_level_traversable(*this, AK::URL("about:blank")).release_value_but_fixme_should_propagate_errors()); } Page::~Page() = default; @@ -161,6 +160,13 @@ bool Page::handle_keyup(KeyCode key, unsigned modifiers, u32 code_point) return focused_context().event_handler().handle_keyup(key, modifiers, code_point); } +void Page::set_top_level_traversable(JS::NonnullGCPtr navigable) +{ + VERIFY(!m_top_level_traversable); // Replacement is not allowed! + VERIFY(navigable->page() == this); + m_top_level_traversable = navigable; +} + bool Page::top_level_traversable_is_initialized() const { return m_top_level_traversable; diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index 003bf234eb..cce3a1911d 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -46,6 +46,8 @@ public: PageClient& client() { return m_client; } PageClient const& client() const { return m_client; } + void set_top_level_traversable(JS::NonnullGCPtr); + // FIXME: This is a hack. bool top_level_traversable_is_initialized() const; diff --git a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp index f0c79a246f..2ad43098a6 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp @@ -50,6 +50,7 @@ ErrorOr> SVGDecodedImageData::create(Page& ho auto page_client = make(host_page); auto page = make(*page_client); page_client->m_svg_page = page.ptr(); + page->set_top_level_traversable(MUST(Web::HTML::TraversableNavigable::create_a_fresh_top_level_traversable(*page, AK::URL("about:blank")))); JS::NonnullGCPtr navigable = page->top_level_traversable(); auto response = Fetch::Infrastructure::Response::create(navigable->vm()); response->url_list().append(url); diff --git a/Userland/Services/WebContent/CMakeLists.txt b/Userland/Services/WebContent/CMakeLists.txt index 02d8729284..cd6637a970 100644 --- a/Userland/Services/WebContent/CMakeLists.txt +++ b/Userland/Services/WebContent/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES ConnectionFromClient.cpp ConsoleGlobalEnvironmentExtensions.cpp ImageCodecPluginSerenity.cpp + PageClient.cpp PageHost.cpp WebContentConsoleClient.cpp WebDriverConnection.cpp diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 0e8ec1a875..9231a8f760 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -4,6 +4,7 @@ * Copyright (c) 2021-2023, Linus Groh * Copyright (c) 2022, Tobias Christiansen * Copyright (c) 2022, Tim Flynn + * Copyright (c) 2023, Andrew Kaster * * SPDX-License-Identifier: BSD-2-Clause */ @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -56,30 +58,30 @@ void ConnectionFromClient::die() Web::Platform::EventLoopPlugin::the().quit(); } -Web::Page& ConnectionFromClient::page() +PageClient& ConnectionFromClient::page(u64 index) { - return m_page_host->page(); + return m_page_host->page(index); } -Web::Page const& ConnectionFromClient::page() const +PageClient const& ConnectionFromClient::page(u64 index) const { - return m_page_host->page(); + return m_page_host->page(index); } Messages::WebContentServer::GetWindowHandleResponse ConnectionFromClient::get_window_handle() { - return m_page_host->page().top_level_browsing_context().window_handle(); + return page().page().top_level_browsing_context().window_handle(); } void ConnectionFromClient::set_window_handle(String const& handle) { - m_page_host->page().top_level_browsing_context().set_window_handle(handle); + page().page().top_level_browsing_context().set_window_handle(handle); } void ConnectionFromClient::connect_to_webdriver(DeprecatedString const& webdriver_ipc_path) { // FIXME: Propagate this error back to the browser. - if (auto result = m_page_host->connect_to_webdriver(webdriver_ipc_path); result.is_error()) + if (auto result = page().connect_to_webdriver(webdriver_ipc_path); result.is_error()) dbgln("Unable to connect to the WebDriver process: {}", result.error()); } @@ -87,7 +89,7 @@ void ConnectionFromClient::update_system_theme(Core::AnonymousBuffer const& them { Gfx::set_system_theme(theme_buffer); auto impl = Gfx::PaletteImpl::create_with_anonymous_buffer(theme_buffer); - m_page_host->set_palette_impl(*impl); + page().set_palette_impl(*impl); } void ConnectionFromClient::update_system_fonts(DeprecatedString const& default_font_query, DeprecatedString const& fixed_width_font_query, DeprecatedString const& window_title_font_query) @@ -99,7 +101,7 @@ void ConnectionFromClient::update_system_fonts(DeprecatedString const& default_f void ConnectionFromClient::update_screen_rects(Vector const& rects, u32 main_screen) { - m_page_host->set_screen_rects(rects, main_screen); + page().set_screen_rects(rects, main_screen); } void ConnectionFromClient::load_url(const URL& url) @@ -116,19 +118,19 @@ void ConnectionFromClient::load_url(const URL& url) pthread_setname_np(pthread_self(), process_name.characters()); #endif - page().load(url); + page().page().load(url); } void ConnectionFromClient::load_html(DeprecatedString const& html) { dbgln_if(SPAM_DEBUG, "handle: WebContentServer::LoadHTML: html={}", html); - page().load_html(html); + page().page().load_html(html); } void ConnectionFromClient::set_viewport_rect(Gfx::IntRect const& rect) { dbgln_if(SPAM_DEBUG, "handle: WebContentServer::SetViewportRect: rect={}", rect); - m_page_host->set_viewport_rect(rect.to_type()); + page().set_viewport_rect(rect.to_type()); } void ConnectionFromClient::add_backing_store(i32 backing_store_id, Gfx::ShareableBitmap const& bitmap) @@ -165,7 +167,7 @@ void ConnectionFromClient::paint(Gfx::IntRect const& content_rect, i32 backing_s void ConnectionFromClient::flush_pending_paint_requests() { for (auto& pending_paint : m_pending_paint_requests) { - m_page_host->paint(pending_paint.content_rect.to_type(), *pending_paint.bitmap); + page().paint(pending_paint.content_rect.to_type(), *pending_paint.bitmap); async_did_paint(pending_paint.content_rect, pending_paint.bitmap_id); } m_pending_paint_requests.clear(); @@ -181,13 +183,13 @@ void ConnectionFromClient::process_next_input_event() [&](QueuedMouseEvent const& event) { switch (event.type) { case QueuedMouseEvent::Type::MouseDown: - report_finished_handling_input_event(page().handle_mousedown( + report_finished_handling_input_event(page().page().handle_mousedown( event.position.to_type(), event.screen_position.to_type(), event.button, event.buttons, event.modifiers)); break; case QueuedMouseEvent::Type::MouseUp: - report_finished_handling_input_event(page().handle_mouseup( + report_finished_handling_input_event(page().page().handle_mouseup( event.position.to_type(), event.screen_position.to_type(), event.button, event.buttons, event.modifiers)); @@ -198,13 +200,13 @@ void ConnectionFromClient::process_next_input_event() for (size_t i = 0; i < event.coalesced_event_count; ++i) { report_finished_handling_input_event(false); } - report_finished_handling_input_event(page().handle_mousemove( + report_finished_handling_input_event(page().page().handle_mousemove( event.position.to_type(), event.screen_position.to_type(), event.buttons, event.modifiers)); break; case QueuedMouseEvent::Type::DoubleClick: - report_finished_handling_input_event(page().handle_doubleclick( + report_finished_handling_input_event(page().page().handle_doubleclick( event.position.to_type(), event.screen_position.to_type(), event.button, event.buttons, event.modifiers)); @@ -213,7 +215,7 @@ void ConnectionFromClient::process_next_input_event() for (size_t i = 0; i < event.coalesced_event_count; ++i) { report_finished_handling_input_event(false); } - report_finished_handling_input_event(page().handle_mousewheel( + report_finished_handling_input_event(page().page().handle_mousewheel( event.position.to_type(), event.screen_position.to_type(), event.button, event.buttons, event.modifiers, event.wheel_delta_x, event.wheel_delta_y)); @@ -223,10 +225,10 @@ void ConnectionFromClient::process_next_input_event() [&](QueuedKeyboardEvent const& event) { switch (event.type) { case QueuedKeyboardEvent::Type::KeyDown: - report_finished_handling_input_event(page().handle_keydown((KeyCode)event.key, event.modifiers, event.code_point)); + report_finished_handling_input_event(page().page().handle_keydown((KeyCode)event.key, event.modifiers, event.code_point)); break; case QueuedKeyboardEvent::Type::KeyUp: - report_finished_handling_input_event(page().handle_keyup((KeyCode)event.key, event.modifiers, event.code_point)); + report_finished_handling_input_event(page().page().handle_keyup((KeyCode)event.key, event.modifiers, event.code_point)); break; } }); @@ -361,18 +363,18 @@ void ConnectionFromClient::report_finished_handling_input_event(bool event_was_h void ConnectionFromClient::debug_request(DeprecatedString const& request, DeprecatedString const& argument) { if (request == "dump-session-history") { - auto const& traversable = page().top_level_traversable(); + auto const& traversable = page().page().top_level_traversable(); Web::dump_tree(*traversable); } if (request == "dump-dom-tree") { - if (auto* doc = page().top_level_browsing_context().active_document()) + if (auto* doc = page().page().top_level_browsing_context().active_document()) Web::dump_tree(*doc); return; } if (request == "dump-layout-tree") { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { if (auto* viewport = doc->layout_node()) Web::dump_tree(*viewport); } @@ -380,7 +382,7 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec } if (request == "dump-paint-tree") { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { if (auto* paintable = doc->paintable()) Web::dump_tree(*paintable); } @@ -388,7 +390,7 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec } if (request == "dump-stacking-context-tree") { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { if (auto* viewport = doc->layout_node()) { if (auto* stacking_context = viewport->paintable_box()->stacking_context()) stacking_context->dump(); @@ -398,7 +400,7 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec } if (request == "dump-style-sheets") { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { for (auto& sheet : doc->style_sheets().sheets()) { if (auto result = Web::dump_sheet(sheet); result.is_error()) dbgln("Failed to dump style sheets: {}", result.error()); @@ -408,7 +410,7 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec } if (request == "dump-all-resolved-styles") { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { Queue elements_to_visit; elements_to_visit.enqueue(doc->document_element()); while (!elements_to_visit.is_empty()) { @@ -440,8 +442,8 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec if (request == "set-line-box-borders") { bool state = argument == "on"; - m_page_host->set_should_show_line_box_borders(state); - page().top_level_traversable()->set_needs_display(page().top_level_traversable()->viewport_rect()); + page().set_should_show_line_box_borders(state); + page().page().top_level_traversable()->set_needs_display(page().page().top_level_traversable()->viewport_rect()); return; } @@ -456,28 +458,28 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec } if (request == "same-origin-policy") { - m_page_host->page().set_same_origin_policy_enabled(argument == "on"); + page().page().set_same_origin_policy_enabled(argument == "on"); return; } if (request == "scripting") { - m_page_host->page().set_is_scripting_enabled(argument == "on"); + page().page().set_is_scripting_enabled(argument == "on"); return; } if (request == "block-pop-ups") { - m_page_host->page().set_should_block_pop_ups(argument == "on"); + page().page().set_should_block_pop_ups(argument == "on"); return; } if (request == "dump-local-storage") { - if (auto* document = page().top_level_browsing_context().active_document()) + if (auto* document = page().page().top_level_browsing_context().active_document()) document->window().local_storage().release_value_but_fixme_should_propagate_errors()->dump(); return; } if (request == "load-reference-page") { - if (auto* document = page().top_level_browsing_context().active_document()) { + if (auto* document = page().page().top_level_browsing_context().active_document()) { auto maybe_link = document->query_selector("link[rel=match]"sv); if (maybe_link.is_error() || !maybe_link.value()) { // To make sure that we fail the ref-test if the link is missing, load the error page. @@ -494,21 +496,21 @@ void ConnectionFromClient::debug_request(DeprecatedString const& request, Deprec void ConnectionFromClient::get_source() { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { async_did_get_source(doc->url(), doc->source()); } } void ConnectionFromClient::inspect_dom_tree() { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { async_did_get_dom_tree(doc->dump_dom_tree_as_json()); } } Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect_dom_node(i32 node_id, Optional const& pseudo_element) { - auto& top_context = page().top_level_browsing_context(); + auto& top_context = page().page().top_level_browsing_context(); top_context.for_each_in_inclusive_subtree([&](auto& ctx) { if (ctx.active_document() != nullptr) { @@ -618,7 +620,7 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect // FIXME: Pseudo-elements only exist as Layout::Nodes, which don't have style information // in a format we can use. So, we run the StyleComputer again to get the specified // values, and have to ignore the computed values and custom properties. - auto pseudo_element_style = MUST(page().focused_context().active_document()->style_computer().compute_style(element, pseudo_element)); + auto pseudo_element_style = MUST(page().page().focused_context().active_document()->style_computer().compute_style(element, pseudo_element)); DeprecatedString computed_values = serialize_json(pseudo_element_style); DeprecatedString resolved_values = "{}"; DeprecatedString custom_properties_json = serialize_custom_properties_json(element, pseudo_element); @@ -639,7 +641,7 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect Messages::WebContentServer::GetHoveredNodeIdResponse ConnectionFromClient::get_hovered_node_id() { - if (auto* document = page().top_level_browsing_context().active_document()) { + if (auto* document = page().page().top_level_browsing_context().active_document()) { auto hovered_node = document->hovered_node(); if (hovered_node) return hovered_node->unique_id(); @@ -647,7 +649,7 @@ Messages::WebContentServer::GetHoveredNodeIdResponse ConnectionFromClient::get_h return (i32)0; } -void ConnectionFromClient::initialize_js_console(Badge, Web::DOM::Document& document) +void ConnectionFromClient::initialize_js_console(Badge, Web::DOM::Document& document) { auto& realm = document.realm(); auto console_object = realm.intrinsics().console_object(); @@ -662,7 +664,7 @@ void ConnectionFromClient::initialize_js_console(Badge, Web::DOM::Docu m_console_clients.set(&document, move(console_client)); } -void ConnectionFromClient::destroy_js_console(Badge, Web::DOM::Document& document) +void ConnectionFromClient::destroy_js_console(Badge, Web::DOM::Document& document) { m_console_clients.remove(&document); } @@ -675,7 +677,7 @@ void ConnectionFromClient::js_console_input(DeprecatedString const& js_source) void ConnectionFromClient::run_javascript(DeprecatedString const& js_source) { - auto* active_document = page().top_level_browsing_context().active_document(); + auto* active_document = page().page().top_level_browsing_context().active_document(); if (!active_document) return; @@ -708,33 +710,33 @@ void ConnectionFromClient::js_console_request_messages(i32 start_index) Messages::WebContentServer::TakeDocumentScreenshotResponse ConnectionFromClient::take_document_screenshot() { - auto* document = page().top_level_browsing_context().active_document(); + auto* document = page().page().top_level_browsing_context().active_document(); if (!document || !document->document_element()) return { {} }; - auto const& content_size = m_page_host->content_size(); + auto const& content_size = page().content_size(); Web::DevicePixelRect rect { { 0, 0 }, content_size }; auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, rect.size().to_type()).release_value_but_fixme_should_propagate_errors(); - m_page_host->paint(rect, *bitmap); + page().paint(rect, *bitmap); return { bitmap->to_shareable_bitmap() }; } Messages::WebContentServer::GetSelectedTextResponse ConnectionFromClient::get_selected_text() { - return page().focused_context().selected_text(); + return page().page().focused_context().selected_text(); } void ConnectionFromClient::select_all() { - page().focused_context().select_all(); - page().client().page_did_change_selection(); + page().page().focused_context().select_all(); + page().page().client().page_did_change_selection(); } Messages::WebContentServer::DumpLayoutTreeResponse ConnectionFromClient::dump_layout_tree() { - auto* document = page().top_level_browsing_context().active_document(); + auto* document = page().page().top_level_browsing_context().active_document(); if (!document) return DeprecatedString { "(no DOM tree)" }; document->update_layout(); @@ -748,7 +750,7 @@ Messages::WebContentServer::DumpLayoutTreeResponse ConnectionFromClient::dump_la Messages::WebContentServer::DumpPaintTreeResponse ConnectionFromClient::dump_paint_tree() { - auto* document = page().top_level_browsing_context().active_document(); + auto* document = page().page().top_level_browsing_context().active_document(); if (!document) return DeprecatedString { "(no DOM tree)" }; document->update_layout(); @@ -764,7 +766,7 @@ Messages::WebContentServer::DumpPaintTreeResponse ConnectionFromClient::dump_pai Messages::WebContentServer::DumpTextResponse ConnectionFromClient::dump_text() { - auto* document = page().top_level_browsing_context().active_document(); + auto* document = page().page().top_level_browsing_context().active_document(); if (!document) return DeprecatedString { "(no DOM tree)" }; if (!document->body()) @@ -807,44 +809,44 @@ void ConnectionFromClient::set_proxy_mappings(Vector const& pr void ConnectionFromClient::set_preferred_color_scheme(Web::CSS::PreferredColorScheme const& color_scheme) { - m_page_host->set_preferred_color_scheme(color_scheme); + page().set_preferred_color_scheme(color_scheme); } void ConnectionFromClient::set_has_focus(bool has_focus) { - m_page_host->set_has_focus(has_focus); + page().set_has_focus(has_focus); } void ConnectionFromClient::set_is_scripting_enabled(bool is_scripting_enabled) { - m_page_host->set_is_scripting_enabled(is_scripting_enabled); + page().set_is_scripting_enabled(is_scripting_enabled); } void ConnectionFromClient::set_device_pixels_per_css_pixel(float device_pixels_per_css_pixel) { - m_page_host->set_device_pixels_per_css_pixel(device_pixels_per_css_pixel); + page().set_device_pixels_per_css_pixel(device_pixels_per_css_pixel); } void ConnectionFromClient::set_window_position(Gfx::IntPoint position) { - m_page_host->set_window_position(position.to_type()); + page().set_window_position(position.to_type()); } void ConnectionFromClient::set_window_size(Gfx::IntSize size) { - m_page_host->set_window_size(size.to_type()); + page().set_window_size(size.to_type()); } Messages::WebContentServer::GetLocalStorageEntriesResponse ConnectionFromClient::get_local_storage_entries() { - auto* document = page().top_level_browsing_context().active_document(); + auto* document = page().page().top_level_browsing_context().active_document(); auto local_storage = document->window().local_storage().release_value_but_fixme_should_propagate_errors(); return local_storage->map(); } Messages::WebContentServer::GetSessionStorageEntriesResponse ConnectionFromClient::get_session_storage_entries() { - auto* document = page().top_level_browsing_context().active_document(); + auto* document = page().page().top_level_browsing_context().active_document(); auto session_storage = document->window().session_storage().release_value_but_fixme_should_propagate_errors(); return session_storage->map(); } @@ -871,7 +873,7 @@ void ConnectionFromClient::request_file(Web::FileRequest file_request) void ConnectionFromClient::set_system_visibility_state(bool visible) { - m_page_host->page().top_level_traversable()->set_system_visibility_state( + page().page().top_level_traversable()->set_system_visibility_state( visible ? Web::HTML::VisibilityState::Visible : Web::HTML::VisibilityState::Hidden); @@ -879,52 +881,52 @@ void ConnectionFromClient::set_system_visibility_state(bool visible) void ConnectionFromClient::alert_closed() { - m_page_host->alert_closed(); + page().page().alert_closed(); } void ConnectionFromClient::confirm_closed(bool accepted) { - m_page_host->confirm_closed(accepted); + page().page().confirm_closed(accepted); } void ConnectionFromClient::prompt_closed(Optional const& response) { - m_page_host->prompt_closed(response); + page().page().prompt_closed(response); } void ConnectionFromClient::color_picker_closed(Optional const& picked_color) { - m_page_host->color_picker_closed(picked_color); + page().page().color_picker_closed(picked_color); } void ConnectionFromClient::toggle_media_play_state() { - m_page_host->toggle_media_play_state().release_value_but_fixme_should_propagate_errors(); + page().page().toggle_media_play_state().release_value_but_fixme_should_propagate_errors(); } void ConnectionFromClient::toggle_media_mute_state() { - m_page_host->toggle_media_mute_state(); + page().page().toggle_media_mute_state(); } void ConnectionFromClient::toggle_media_loop_state() { - m_page_host->toggle_media_loop_state().release_value_but_fixme_should_propagate_errors(); + page().page().toggle_media_loop_state().release_value_but_fixme_should_propagate_errors(); } void ConnectionFromClient::toggle_media_controls_state() { - m_page_host->toggle_media_controls_state().release_value_but_fixme_should_propagate_errors(); + page().page().toggle_media_controls_state().release_value_but_fixme_should_propagate_errors(); } void ConnectionFromClient::set_user_style(String const& source) { - m_page_host->set_user_style(source); + page().page().set_user_style(source); } void ConnectionFromClient::inspect_accessibility_tree() { - if (auto* doc = page().top_level_browsing_context().active_document()) { + if (auto* doc = page().page().top_level_browsing_context().active_document()) { async_did_get_accessibility_tree(doc->dump_accessibility_tree_as_json()); } } diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index d3aa1981a0..769f1d2d7a 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -33,8 +33,8 @@ public: virtual void die() override; - void initialize_js_console(Badge, Web::DOM::Document& document); - void destroy_js_console(Badge, Web::DOM::Document& document); + void initialize_js_console(Badge, Web::DOM::Document& document); + void destroy_js_console(Badge, Web::DOM::Document& document); void request_file(Web::FileRequest); @@ -46,8 +46,8 @@ public: private: explicit ConnectionFromClient(NonnullOwnPtr); - Web::Page& page(); - Web::Page const& page() const; + PageClient& page(u64 index = 0); + PageClient const& page(u64 index = 0) const; virtual Messages::WebContentServer::GetWindowHandleResponse get_window_handle() override; virtual void set_window_handle(String const& handle) override; diff --git a/Userland/Services/WebContent/Forward.h b/Userland/Services/WebContent/Forward.h index 160588a103..c949cb5af0 100644 --- a/Userland/Services/WebContent/Forward.h +++ b/Userland/Services/WebContent/Forward.h @@ -11,6 +11,7 @@ namespace WebContent { class ConnectionFromClient; class ConsoleGlobalEnvironmentExtensions; class PageHost; +class PageClient; class WebContentConsoleClient; class WebDriverConnection; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp new file mode 100644 index 0000000000..b16c1da3d7 --- /dev/null +++ b/Userland/Services/WebContent/PageClient.cpp @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2020-2023, Andreas Kling + * Copyright (c) 2021-2022, Linus Groh + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAS_ACCELERATED_GRAPHICS +# include +#endif + +namespace WebContent { + +static bool s_use_gpu_painter = false; + +void PageClient::set_use_gpu_painter() +{ + s_use_gpu_painter = true; +} + +PageClient::PageClient(PageHost& owner, u64 id) + : m_owner(owner) + , m_page(make(*this)) + , m_id(id) +{ + setup_palette(); + m_invalidation_coalescing_timer = Web::Platform::Timer::create_single_shot(0, [this] { + client().async_did_invalidate_content_rect({ m_invalidation_rect.x().value(), m_invalidation_rect.y().value(), m_invalidation_rect.width().value(), m_invalidation_rect.height().value() }); + m_invalidation_rect = {}; + }); +} + +ConnectionFromClient& PageClient::client() const +{ + return m_owner.client(); +} + +void PageClient::set_has_focus(bool has_focus) +{ + m_has_focus = has_focus; +} + +void PageClient::setup_palette() +{ + // FIXME: Get the proper palette from our peer somehow + auto buffer_or_error = Core::AnonymousBuffer::create_with_size(sizeof(Gfx::SystemTheme)); + VERIFY(!buffer_or_error.is_error()); + auto buffer = buffer_or_error.release_value(); + auto* theme = buffer.data(); + theme->color[(int)Gfx::ColorRole::Window] = Color::Magenta; + theme->color[(int)Gfx::ColorRole::WindowText] = Color::Cyan; + m_palette_impl = Gfx::PaletteImpl::create_with_anonymous_buffer(buffer); +} + +bool PageClient::is_connection_open() const +{ + return client().is_open(); +} + +Gfx::Palette PageClient::palette() const +{ + return Gfx::Palette(*m_palette_impl); +} + +void PageClient::set_palette_impl(Gfx::PaletteImpl& impl) +{ + m_palette_impl = impl; + if (auto* document = page().top_level_browsing_context().active_document()) + document->invalidate_style(); +} + +void PageClient::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme) +{ + m_preferred_color_scheme = color_scheme; + if (auto* document = page().top_level_browsing_context().active_document()) + document->invalidate_style(); +} + +void PageClient::set_is_scripting_enabled(bool is_scripting_enabled) +{ + page().set_is_scripting_enabled(is_scripting_enabled); +} + +void PageClient::set_window_position(Web::DevicePixelPoint position) +{ + page().set_window_position(position); +} + +void PageClient::set_window_size(Web::DevicePixelSize size) +{ + page().set_window_size(size); +} + +Web::Layout::Viewport* PageClient::layout_root() +{ + auto* document = page().top_level_browsing_context().active_document(); + if (!document) + return nullptr; + return document->layout_node(); +} + +Gfx::Color PageClient::background_color() const +{ + auto document = page().top_level_browsing_context().active_document(); + if (!document) + return Gfx::Color::Transparent; + return document->background_color(); +} + +void PageClient::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target) +{ + Gfx::IntRect bitmap_rect { {}, content_rect.size().to_type() }; + + auto document = page().top_level_browsing_context().active_document(); + if (document) { + document->update_layout(); + } + + auto background_color = this->background_color(); + + Web::Painting::RecordingPainter recording_painter; + Web::PaintContext context(recording_painter, palette(), device_pixels_per_css_pixel()); + + if (background_color.alpha() < 255) + recording_painter.fill_rect(bitmap_rect, Web::CSS::SystemColor::canvas()); + recording_painter.fill_rect(bitmap_rect, background_color); + + if (!document->paintable()) + return; + + context.set_should_show_line_box_borders(m_should_show_line_box_borders); + context.set_device_viewport_rect(content_rect); + context.set_has_focus(m_has_focus); + document->paintable()->paint_all_phases(context); + + if (s_use_gpu_painter) { +#ifdef HAS_ACCELERATED_GRAPHICS + Web::Painting::PaintingCommandExecutorGPU painting_command_executor(target); + recording_painter.execute(painting_command_executor); +#endif + } else { + Web::Painting::PaintingCommandExecutorCPU painting_command_executor(target); + recording_painter.execute(painting_command_executor); + } +} + +void PageClient::set_viewport_rect(Web::DevicePixelRect const& rect) +{ + page().top_level_traversable()->set_viewport_rect(page().device_to_css_rect(rect)); +} + +void PageClient::page_did_invalidate(Web::CSSPixelRect const& content_rect) +{ + m_invalidation_rect = m_invalidation_rect.united(page().enclosing_device_rect(content_rect)); + if (!m_invalidation_coalescing_timer->is_active()) + m_invalidation_coalescing_timer->start(); +} + +void PageClient::page_did_change_selection() +{ + client().async_did_change_selection(); +} + +void PageClient::page_did_request_cursor_change(Gfx::StandardCursor cursor) +{ + client().async_did_request_cursor_change((u32)cursor); +} + +void PageClient::page_did_layout() +{ + auto* layout_root = this->layout_root(); + VERIFY(layout_root); + if (layout_root->paintable_box()->has_scrollable_overflow()) + m_content_size = page().enclosing_device_rect(layout_root->paintable_box()->scrollable_overflow_rect().value()).size(); + else + m_content_size = page().enclosing_device_rect(layout_root->paintable_box()->absolute_rect()).size(); + client().async_did_layout(m_content_size.to_type()); +} + +void PageClient::page_did_change_title(DeprecatedString const& title) +{ + client().async_did_change_title(title); +} + +void PageClient::page_did_request_navigate_back() +{ + client().async_did_request_navigate_back(); +} + +void PageClient::page_did_request_navigate_forward() +{ + client().async_did_request_navigate_forward(); +} + +void PageClient::page_did_request_refresh() +{ + client().async_did_request_refresh(); +} + +Gfx::IntSize PageClient::page_did_request_resize_window(Gfx::IntSize size) +{ + return client().did_request_resize_window(size); +} + +Gfx::IntPoint PageClient::page_did_request_reposition_window(Gfx::IntPoint position) +{ + return client().did_request_reposition_window(position); +} + +void PageClient::page_did_request_restore_window() +{ + client().async_did_request_restore_window(); +} + +Gfx::IntRect PageClient::page_did_request_maximize_window() +{ + return client().did_request_maximize_window(); +} + +Gfx::IntRect PageClient::page_did_request_minimize_window() +{ + return client().did_request_minimize_window(); +} + +Gfx::IntRect PageClient::page_did_request_fullscreen_window() +{ + return client().did_request_fullscreen_window(); +} + +void PageClient::page_did_request_scroll(i32 x_delta, i32 y_delta) +{ + client().async_did_request_scroll(x_delta, y_delta); +} + +void PageClient::page_did_request_scroll_to(Web::CSSPixelPoint scroll_position) +{ + auto device_scroll_position = page().css_to_device_point(scroll_position); + client().async_did_request_scroll_to(device_scroll_position.to_type()); +} + +void PageClient::page_did_request_scroll_into_view(Web::CSSPixelRect const& rect) +{ + auto device_pixel_rect = page().enclosing_device_rect(rect); + client().async_did_request_scroll_into_view({ device_pixel_rect.x().value(), + device_pixel_rect.y().value(), + device_pixel_rect.width().value(), + device_pixel_rect.height().value() }); +} + +void PageClient::page_did_enter_tooltip_area(Web::CSSPixelPoint content_position, DeprecatedString const& title) +{ + client().async_did_enter_tooltip_area({ content_position.x().to_int(), content_position.y().to_int() }, title); +} + +void PageClient::page_did_leave_tooltip_area() +{ + client().async_did_leave_tooltip_area(); +} + +void PageClient::page_did_hover_link(const URL& url) +{ + client().async_did_hover_link(url); +} + +void PageClient::page_did_unhover_link() +{ + client().async_did_unhover_link(); +} + +void PageClient::page_did_click_link(const URL& url, DeprecatedString const& target, unsigned modifiers) +{ + client().async_did_click_link(url, target, modifiers); +} + +void PageClient::page_did_middle_click_link(const URL& url, [[maybe_unused]] DeprecatedString const& target, [[maybe_unused]] unsigned modifiers) +{ + client().async_did_middle_click_link(url, target, modifiers); +} + +void PageClient::page_did_start_loading(const URL& url, bool is_redirect) +{ + client().async_did_start_loading(url, is_redirect); +} + +void PageClient::page_did_create_new_document(Web::DOM::Document& document) +{ + client().initialize_js_console({}, document); +} + +void PageClient::page_did_destroy_document(Web::DOM::Document& document) +{ + client().destroy_js_console({}, document); +} + +void PageClient::page_did_finish_loading(const URL& url) +{ + client().async_did_finish_loading(url); +} + +void PageClient::page_did_finish_text_test() +{ + client().async_did_finish_text_test(); +} + +void PageClient::page_did_request_context_menu(Web::CSSPixelPoint content_position) +{ + client().async_did_request_context_menu(page().css_to_device_point(content_position).to_type()); +} + +void PageClient::page_did_request_link_context_menu(Web::CSSPixelPoint content_position, URL const& url, DeprecatedString const& target, unsigned modifiers) +{ + client().async_did_request_link_context_menu(page().css_to_device_point(content_position).to_type(), url, target, modifiers); +} + +void PageClient::page_did_request_image_context_menu(Web::CSSPixelPoint content_position, URL const& url, DeprecatedString const& target, unsigned modifiers, Gfx::Bitmap const* bitmap_pointer) +{ + auto bitmap = bitmap_pointer ? bitmap_pointer->to_shareable_bitmap() : Gfx::ShareableBitmap(); + client().async_did_request_image_context_menu(page().css_to_device_point(content_position).to_type(), url, target, modifiers, bitmap); +} + +void PageClient::page_did_request_media_context_menu(Web::CSSPixelPoint content_position, DeprecatedString const& target, unsigned modifiers, Web::Page::MediaContextMenu menu) +{ + client().async_did_request_media_context_menu(page().css_to_device_point(content_position).to_type(), target, modifiers, move(menu)); +} + +void PageClient::page_did_request_alert(String const& message) +{ + client().async_did_request_alert(message); +} + +void PageClient::alert_closed() +{ + page().alert_closed(); +} + +void PageClient::page_did_request_confirm(String const& message) +{ + client().async_did_request_confirm(message); +} + +void PageClient::confirm_closed(bool accepted) +{ + page().confirm_closed(accepted); +} + +void PageClient::page_did_request_prompt(String const& message, String const& default_) +{ + client().async_did_request_prompt(message, default_); +} + +void PageClient::page_did_request_set_prompt_text(String const& text) +{ + client().async_did_request_set_prompt_text(text); +} + +void PageClient::prompt_closed(Optional response) +{ + page().prompt_closed(move(response)); +} + +void PageClient::color_picker_closed(Optional picked_color) +{ + page().color_picker_closed(picked_color); +} + +Web::WebIDL::ExceptionOr PageClient::toggle_media_play_state() +{ + return page().toggle_media_play_state(); +} + +void PageClient::toggle_media_mute_state() +{ + page().toggle_media_mute_state(); +} + +Web::WebIDL::ExceptionOr PageClient::toggle_media_loop_state() +{ + return page().toggle_media_loop_state(); +} + +Web::WebIDL::ExceptionOr PageClient::toggle_media_controls_state() +{ + return page().toggle_media_controls_state(); +} + +void PageClient::set_user_style(String source) +{ + page().set_user_style(source); +} + +void PageClient::page_did_request_accept_dialog() +{ + client().async_did_request_accept_dialog(); +} + +void PageClient::page_did_request_dismiss_dialog() +{ + client().async_did_request_dismiss_dialog(); +} + +void PageClient::page_did_change_favicon(Gfx::Bitmap const& favicon) +{ + client().async_did_change_favicon(favicon.to_shareable_bitmap()); +} + +Vector PageClient::page_did_request_all_cookies(URL const& url) +{ + return client().did_request_all_cookies(url); +} + +Optional PageClient::page_did_request_named_cookie(URL const& url, DeprecatedString const& name) +{ + return client().did_request_named_cookie(url, name); +} + +DeprecatedString PageClient::page_did_request_cookie(const URL& url, Web::Cookie::Source source) +{ + auto response = client().send_sync_but_allow_failure(move(url), static_cast(source)); + if (!response) { + dbgln("WebContent client disconnected during DidRequestCookie. Exiting peacefully."); + exit(0); + } + return response->take_cookie(); +} + +void PageClient::page_did_set_cookie(const URL& url, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source) +{ + client().async_did_set_cookie(url, cookie, static_cast(source)); +} + +void PageClient::page_did_update_cookie(Web::Cookie::Cookie cookie) +{ + client().async_did_update_cookie(move(cookie)); +} + +void PageClient::page_did_update_resource_count(i32 count_waiting) +{ + client().async_did_update_resource_count(count_waiting); +} + +String PageClient::page_did_request_new_tab(Web::HTML::ActivateTab activate_tab) +{ + return client().did_request_new_tab(activate_tab); +} + +void PageClient::page_did_request_activate_tab() +{ + client().async_did_request_activate_tab(); +} + +void PageClient::page_did_close_browsing_context(Web::HTML::BrowsingContext const&) +{ + client().async_did_close_browsing_context(); +} + +void PageClient::request_file(Web::FileRequest file_request) +{ + client().request_file(move(file_request)); +} + +void PageClient::page_did_request_color_picker(Color current_color) +{ + client().async_did_request_color_picker(current_color); +} + +void PageClient::page_did_change_theme_color(Gfx::Color color) +{ + client().async_did_change_theme_color(color); +} + +void PageClient::page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) +{ + client().async_did_insert_clipboard_entry(move(data), move(presentation_style), move(mime_type)); +} + +void PageClient::inspector_did_load() +{ + client().async_inspector_did_load(); +} + +void PageClient::inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) +{ + client().async_inspector_did_select_dom_node(node_id, pseudo_element); +} + +ErrorOr PageClient::connect_to_webdriver(DeprecatedString const& webdriver_ipc_path) +{ + VERIFY(!m_webdriver); + m_webdriver = TRY(WebDriverConnection::connect(*this, webdriver_ipc_path)); + + if (m_owner.on_webdriver_connection) + m_owner.on_webdriver_connection(*m_webdriver); + + return {}; +} + +} diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h new file mode 100644 index 0000000000..132a214ff5 --- /dev/null +++ b/Userland/Services/WebContent/PageClient.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2020-2023, Andreas Kling + * Copyright (c) 2021-2022, Linus Groh + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace WebContent { + +class PageClient final : public Web::PageClient { + AK_MAKE_NONCOPYABLE(PageClient); + AK_MAKE_NONMOVABLE(PageClient); + +public: + PageClient(PageHost&, u64 id); + + static void set_use_gpu_painter(); + + virtual Web::Page& page() override { return *m_page; } + virtual Web::Page const& page() const override { return *m_page; } + + ErrorOr connect_to_webdriver(DeprecatedString const& webdriver_ipc_path); + + virtual void paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap&) override; + + void set_palette_impl(Gfx::PaletteImpl&); + void set_viewport_rect(Web::DevicePixelRect const&); + void set_screen_rects(Vector const& rects, size_t main_screen_index) { m_screen_rect = rects[main_screen_index].to_type(); } + void set_device_pixels_per_css_pixel(float device_pixels_per_css_pixel) { m_device_pixels_per_css_pixel = device_pixels_per_css_pixel; } + void set_preferred_color_scheme(Web::CSS::PreferredColorScheme); + void set_should_show_line_box_borders(bool b) { m_should_show_line_box_borders = b; } + void set_has_focus(bool); + void set_is_scripting_enabled(bool); + void set_window_position(Web::DevicePixelPoint); + void set_window_size(Web::DevicePixelSize); + + Web::DevicePixelSize content_size() const { return m_content_size; } + + Web::WebIDL::ExceptionOr toggle_media_play_state(); + void toggle_media_mute_state(); + Web::WebIDL::ExceptionOr toggle_media_loop_state(); + Web::WebIDL::ExceptionOr toggle_media_controls_state(); + + void alert_closed(); + void confirm_closed(bool accepted); + void prompt_closed(Optional response); + void color_picker_closed(Optional picked_color); + + [[nodiscard]] Gfx::Color background_color() const; + + void set_user_style(String source); + +private: + // ^PageClient + virtual bool is_connection_open() const override; + virtual Gfx::Palette palette() const override; + virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; } + virtual double device_pixels_per_css_pixel() const override { return m_device_pixels_per_css_pixel; } + virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; } + virtual void page_did_invalidate(Web::CSSPixelRect const&) override; + virtual void page_did_change_selection() override; + virtual void page_did_request_cursor_change(Gfx::StandardCursor) override; + virtual void page_did_layout() override; + virtual void page_did_change_title(DeprecatedString const&) override; + virtual void page_did_request_navigate_back() override; + virtual void page_did_request_navigate_forward() override; + virtual void page_did_request_refresh() override; + virtual Gfx::IntSize page_did_request_resize_window(Gfx::IntSize) override; + virtual Gfx::IntPoint page_did_request_reposition_window(Gfx::IntPoint) override; + virtual void page_did_request_restore_window() override; + virtual Gfx::IntRect page_did_request_maximize_window() override; + virtual Gfx::IntRect page_did_request_minimize_window() override; + virtual Gfx::IntRect page_did_request_fullscreen_window() override; + virtual void page_did_request_scroll(i32, i32) override; + virtual void page_did_request_scroll_to(Web::CSSPixelPoint) override; + virtual void page_did_request_scroll_into_view(Web::CSSPixelRect const&) override; + virtual void page_did_enter_tooltip_area(Web::CSSPixelPoint, DeprecatedString const&) override; + virtual void page_did_leave_tooltip_area() override; + virtual void page_did_hover_link(const URL&) override; + virtual void page_did_unhover_link() override; + virtual void page_did_click_link(const URL&, DeprecatedString const& target, unsigned modifiers) override; + virtual void page_did_middle_click_link(const URL&, DeprecatedString const& target, unsigned modifiers) override; + virtual void page_did_request_context_menu(Web::CSSPixelPoint) override; + virtual void page_did_request_link_context_menu(Web::CSSPixelPoint, URL const&, DeprecatedString const& target, unsigned modifiers) override; + virtual void page_did_request_image_context_menu(Web::CSSPixelPoint, const URL&, DeprecatedString const& target, unsigned modifiers, Gfx::Bitmap const*) override; + virtual void page_did_request_media_context_menu(Web::CSSPixelPoint, DeprecatedString const& target, unsigned modifiers, Web::Page::MediaContextMenu) override; + virtual void page_did_start_loading(const URL&, bool) override; + virtual void page_did_create_new_document(Web::DOM::Document&) override; + virtual void page_did_destroy_document(Web::DOM::Document&) override; + virtual void page_did_finish_loading(const URL&) override; + virtual void page_did_request_alert(String const&) override; + virtual void page_did_request_confirm(String const&) override; + virtual void page_did_request_prompt(String const&, String const&) override; + virtual void page_did_request_set_prompt_text(String const&) override; + virtual void page_did_request_accept_dialog() override; + virtual void page_did_request_dismiss_dialog() override; + virtual void page_did_change_favicon(Gfx::Bitmap const&) override; + virtual Vector page_did_request_all_cookies(URL const&) override; + virtual Optional page_did_request_named_cookie(URL const&, DeprecatedString const&) override; + virtual DeprecatedString page_did_request_cookie(const URL&, Web::Cookie::Source) override; + virtual void page_did_set_cookie(const URL&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override; + virtual void page_did_update_cookie(Web::Cookie::Cookie) override; + virtual void page_did_update_resource_count(i32) override; + virtual String page_did_request_new_tab(Web::HTML::ActivateTab activate_tab) override; + virtual void page_did_request_activate_tab() override; + virtual void page_did_close_browsing_context(Web::HTML::BrowsingContext const&) override; + virtual void request_file(Web::FileRequest) override; + virtual void page_did_request_color_picker(Color current_color) override; + virtual void page_did_finish_text_test() override; + virtual void page_did_change_theme_color(Gfx::Color color) override; + virtual void page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) override; + virtual void inspector_did_load() override; + virtual void inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) override; + + Web::Layout::Viewport* layout_root(); + void setup_palette(); + ConnectionFromClient& client() const; + + PageHost& m_owner; + NonnullOwnPtr m_page; + RefPtr m_palette_impl; + Web::DevicePixelRect m_screen_rect; + Web::DevicePixelSize m_content_size; + float m_device_pixels_per_css_pixel { 1.0f }; + u64 m_id { 0 }; + bool m_should_show_line_box_borders { false }; + bool m_has_focus { false }; + + RefPtr m_invalidation_coalescing_timer; + Web::DevicePixelRect m_invalidation_rect; + Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto }; + + RefPtr m_webdriver; +}; + +} diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index 9c2ad87730..b61d4bbd99 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -1,12 +1,14 @@ /* * Copyright (c) 2020-2023, Andreas Kling * Copyright (c) 2021-2022, Linus Groh + * Copyright (c) 2023, Andrew Kaster * * SPDX-License-Identifier: BSD-2-Clause */ #include "PageHost.h" #include "ConnectionFromClient.h" +#include "PageClient.h" #include #include #include @@ -27,483 +29,20 @@ namespace WebContent { -static bool s_use_gpu_painter = false; - -void PageHost::set_use_gpu_painter() -{ - s_use_gpu_painter = true; -} - PageHost::PageHost(ConnectionFromClient& client) : m_client(client) - , m_page(make(*this)) { - setup_palette(); - m_invalidation_coalescing_timer = Web::Platform::Timer::create_single_shot(0, [this] { - m_client.async_did_invalidate_content_rect({ m_invalidation_rect.x().value(), m_invalidation_rect.y().value(), m_invalidation_rect.width().value(), m_invalidation_rect.height().value() }); - m_invalidation_rect = {}; - }); + auto& first_page = create_page(); + first_page.page().set_top_level_traversable(Web::HTML::TraversableNavigable::create_a_fresh_top_level_traversable(first_page.page(), AK::URL("about:blank")).release_value_but_fixme_should_propagate_errors()); +} + +PageClient& PageHost::create_page() +{ + m_pages.set(m_next_id, make(*this, m_next_id)); + ++m_next_id; + return *m_pages.get(m_next_id - 1).value(); } PageHost::~PageHost() = default; -void PageHost::set_has_focus(bool has_focus) -{ - m_has_focus = has_focus; -} - -void PageHost::setup_palette() -{ - // FIXME: Get the proper palette from our peer somehow - auto buffer_or_error = Core::AnonymousBuffer::create_with_size(sizeof(Gfx::SystemTheme)); - VERIFY(!buffer_or_error.is_error()); - auto buffer = buffer_or_error.release_value(); - auto* theme = buffer.data(); - theme->color[(int)Gfx::ColorRole::Window] = Color::Magenta; - theme->color[(int)Gfx::ColorRole::WindowText] = Color::Cyan; - m_palette_impl = Gfx::PaletteImpl::create_with_anonymous_buffer(buffer); -} - -bool PageHost::is_connection_open() const -{ - return m_client.is_open(); -} - -Gfx::Palette PageHost::palette() const -{ - return Gfx::Palette(*m_palette_impl); -} - -void PageHost::set_palette_impl(Gfx::PaletteImpl& impl) -{ - m_palette_impl = impl; - if (auto* document = page().top_level_browsing_context().active_document()) - document->invalidate_style(); -} - -void PageHost::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme) -{ - m_preferred_color_scheme = color_scheme; - if (auto* document = page().top_level_browsing_context().active_document()) - document->invalidate_style(); -} - -void PageHost::set_is_scripting_enabled(bool is_scripting_enabled) -{ - page().set_is_scripting_enabled(is_scripting_enabled); -} - -void PageHost::set_window_position(Web::DevicePixelPoint position) -{ - page().set_window_position(position); -} - -void PageHost::set_window_size(Web::DevicePixelSize size) -{ - page().set_window_size(size); -} - -ErrorOr PageHost::connect_to_webdriver(DeprecatedString const& webdriver_ipc_path) -{ - VERIFY(!m_webdriver); - m_webdriver = TRY(WebDriverConnection::connect(*this, webdriver_ipc_path)); - - if (on_webdriver_connection) - on_webdriver_connection(*m_webdriver); - - return {}; -} - -Web::Layout::Viewport* PageHost::layout_root() -{ - auto* document = page().top_level_browsing_context().active_document(); - if (!document) - return nullptr; - return document->layout_node(); -} - -Gfx::Color PageHost::background_color() const -{ - auto document = page().top_level_browsing_context().active_document(); - if (!document) - return Gfx::Color::Transparent; - return document->background_color(); -} - -void PageHost::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target) -{ - Gfx::IntRect bitmap_rect { {}, content_rect.size().to_type() }; - - auto document = page().top_level_browsing_context().active_document(); - if (document) { - document->update_layout(); - } - - auto background_color = this->background_color(); - - Web::Painting::RecordingPainter recording_painter; - Web::PaintContext context(recording_painter, palette(), device_pixels_per_css_pixel()); - - if (background_color.alpha() < 255) - recording_painter.fill_rect(bitmap_rect, Web::CSS::SystemColor::canvas()); - recording_painter.fill_rect(bitmap_rect, background_color); - - if (!document->paintable()) - return; - - context.set_should_show_line_box_borders(m_should_show_line_box_borders); - context.set_device_viewport_rect(content_rect); - context.set_has_focus(m_has_focus); - document->paintable()->paint_all_phases(context); - - if (s_use_gpu_painter) { -#ifdef HAS_ACCELERATED_GRAPHICS - Web::Painting::PaintingCommandExecutorGPU painting_command_executor(target); - recording_painter.execute(painting_command_executor); -#endif - } else { - Web::Painting::PaintingCommandExecutorCPU painting_command_executor(target); - recording_painter.execute(painting_command_executor); - } -} - -void PageHost::set_viewport_rect(Web::DevicePixelRect const& rect) -{ - page().top_level_traversable()->set_viewport_rect(page().device_to_css_rect(rect)); -} - -void PageHost::page_did_invalidate(Web::CSSPixelRect const& content_rect) -{ - m_invalidation_rect = m_invalidation_rect.united(page().enclosing_device_rect(content_rect)); - if (!m_invalidation_coalescing_timer->is_active()) - m_invalidation_coalescing_timer->start(); -} - -void PageHost::page_did_change_selection() -{ - m_client.async_did_change_selection(); -} - -void PageHost::page_did_request_cursor_change(Gfx::StandardCursor cursor) -{ - m_client.async_did_request_cursor_change((u32)cursor); -} - -void PageHost::page_did_layout() -{ - auto* layout_root = this->layout_root(); - VERIFY(layout_root); - if (layout_root->paintable_box()->has_scrollable_overflow()) - m_content_size = page().enclosing_device_rect(layout_root->paintable_box()->scrollable_overflow_rect().value()).size(); - else - m_content_size = page().enclosing_device_rect(layout_root->paintable_box()->absolute_rect()).size(); - m_client.async_did_layout(m_content_size.to_type()); -} - -void PageHost::page_did_change_title(DeprecatedString const& title) -{ - m_client.async_did_change_title(title); -} - -void PageHost::page_did_request_navigate_back() -{ - m_client.async_did_request_navigate_back(); -} - -void PageHost::page_did_request_navigate_forward() -{ - m_client.async_did_request_navigate_forward(); -} - -void PageHost::page_did_request_refresh() -{ - m_client.async_did_request_refresh(); -} - -Gfx::IntSize PageHost::page_did_request_resize_window(Gfx::IntSize size) -{ - return m_client.did_request_resize_window(size); -} - -Gfx::IntPoint PageHost::page_did_request_reposition_window(Gfx::IntPoint position) -{ - return m_client.did_request_reposition_window(position); -} - -void PageHost::page_did_request_restore_window() -{ - m_client.async_did_request_restore_window(); -} - -Gfx::IntRect PageHost::page_did_request_maximize_window() -{ - return m_client.did_request_maximize_window(); -} - -Gfx::IntRect PageHost::page_did_request_minimize_window() -{ - return m_client.did_request_minimize_window(); -} - -Gfx::IntRect PageHost::page_did_request_fullscreen_window() -{ - return m_client.did_request_fullscreen_window(); -} - -void PageHost::page_did_request_scroll(i32 x_delta, i32 y_delta) -{ - m_client.async_did_request_scroll(x_delta, y_delta); -} - -void PageHost::page_did_request_scroll_to(Web::CSSPixelPoint scroll_position) -{ - auto device_scroll_position = page().css_to_device_point(scroll_position); - m_client.async_did_request_scroll_to(device_scroll_position.to_type()); -} - -void PageHost::page_did_request_scroll_into_view(Web::CSSPixelRect const& rect) -{ - auto device_pixel_rect = page().enclosing_device_rect(rect); - m_client.async_did_request_scroll_into_view({ device_pixel_rect.x().value(), - device_pixel_rect.y().value(), - device_pixel_rect.width().value(), - device_pixel_rect.height().value() }); -} - -void PageHost::page_did_enter_tooltip_area(Web::CSSPixelPoint content_position, DeprecatedString const& title) -{ - m_client.async_did_enter_tooltip_area({ content_position.x().to_int(), content_position.y().to_int() }, title); -} - -void PageHost::page_did_leave_tooltip_area() -{ - m_client.async_did_leave_tooltip_area(); -} - -void PageHost::page_did_hover_link(const URL& url) -{ - m_client.async_did_hover_link(url); -} - -void PageHost::page_did_unhover_link() -{ - m_client.async_did_unhover_link(); -} - -void PageHost::page_did_click_link(const URL& url, DeprecatedString const& target, unsigned modifiers) -{ - m_client.async_did_click_link(url, target, modifiers); -} - -void PageHost::page_did_middle_click_link(const URL& url, [[maybe_unused]] DeprecatedString const& target, [[maybe_unused]] unsigned modifiers) -{ - m_client.async_did_middle_click_link(url, target, modifiers); -} - -void PageHost::page_did_start_loading(const URL& url, bool is_redirect) -{ - m_client.async_did_start_loading(url, is_redirect); -} - -void PageHost::page_did_create_new_document(Web::DOM::Document& document) -{ - m_client.initialize_js_console({}, document); -} - -void PageHost::page_did_destroy_document(Web::DOM::Document& document) -{ - m_client.destroy_js_console({}, document); -} - -void PageHost::page_did_finish_loading(const URL& url) -{ - m_client.async_did_finish_loading(url); -} - -void PageHost::page_did_finish_text_test() -{ - m_client.async_did_finish_text_test(); -} - -void PageHost::page_did_request_context_menu(Web::CSSPixelPoint content_position) -{ - m_client.async_did_request_context_menu(page().css_to_device_point(content_position).to_type()); -} - -void PageHost::page_did_request_link_context_menu(Web::CSSPixelPoint content_position, URL const& url, DeprecatedString const& target, unsigned modifiers) -{ - m_client.async_did_request_link_context_menu(page().css_to_device_point(content_position).to_type(), url, target, modifiers); -} - -void PageHost::page_did_request_image_context_menu(Web::CSSPixelPoint content_position, URL const& url, DeprecatedString const& target, unsigned modifiers, Gfx::Bitmap const* bitmap_pointer) -{ - auto bitmap = bitmap_pointer ? bitmap_pointer->to_shareable_bitmap() : Gfx::ShareableBitmap(); - m_client.async_did_request_image_context_menu(page().css_to_device_point(content_position).to_type(), url, target, modifiers, bitmap); -} - -void PageHost::page_did_request_media_context_menu(Web::CSSPixelPoint content_position, DeprecatedString const& target, unsigned modifiers, Web::Page::MediaContextMenu menu) -{ - m_client.async_did_request_media_context_menu(page().css_to_device_point(content_position).to_type(), target, modifiers, move(menu)); -} - -void PageHost::page_did_request_alert(String const& message) -{ - m_client.async_did_request_alert(message); -} - -void PageHost::alert_closed() -{ - page().alert_closed(); -} - -void PageHost::page_did_request_confirm(String const& message) -{ - m_client.async_did_request_confirm(message); -} - -void PageHost::confirm_closed(bool accepted) -{ - page().confirm_closed(accepted); -} - -void PageHost::page_did_request_prompt(String const& message, String const& default_) -{ - m_client.async_did_request_prompt(message, default_); -} - -void PageHost::page_did_request_set_prompt_text(String const& text) -{ - m_client.async_did_request_set_prompt_text(text); -} - -void PageHost::prompt_closed(Optional response) -{ - page().prompt_closed(move(response)); -} - -void PageHost::color_picker_closed(Optional picked_color) -{ - page().color_picker_closed(picked_color); -} - -Web::WebIDL::ExceptionOr PageHost::toggle_media_play_state() -{ - return page().toggle_media_play_state(); -} - -void PageHost::toggle_media_mute_state() -{ - page().toggle_media_mute_state(); -} - -Web::WebIDL::ExceptionOr PageHost::toggle_media_loop_state() -{ - return page().toggle_media_loop_state(); -} - -Web::WebIDL::ExceptionOr PageHost::toggle_media_controls_state() -{ - return page().toggle_media_controls_state(); -} - -void PageHost::set_user_style(String source) -{ - page().set_user_style(source); -} - -void PageHost::page_did_request_accept_dialog() -{ - m_client.async_did_request_accept_dialog(); -} - -void PageHost::page_did_request_dismiss_dialog() -{ - m_client.async_did_request_dismiss_dialog(); -} - -void PageHost::page_did_change_favicon(Gfx::Bitmap const& favicon) -{ - m_client.async_did_change_favicon(favicon.to_shareable_bitmap()); -} - -Vector PageHost::page_did_request_all_cookies(URL const& url) -{ - return m_client.did_request_all_cookies(url); -} - -Optional PageHost::page_did_request_named_cookie(URL const& url, DeprecatedString const& name) -{ - return m_client.did_request_named_cookie(url, name); -} - -DeprecatedString PageHost::page_did_request_cookie(const URL& url, Web::Cookie::Source source) -{ - auto response = m_client.send_sync_but_allow_failure(move(url), static_cast(source)); - if (!response) { - dbgln("WebContent client disconnected during DidRequestCookie. Exiting peacefully."); - exit(0); - } - return response->take_cookie(); -} - -void PageHost::page_did_set_cookie(const URL& url, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source) -{ - m_client.async_did_set_cookie(url, cookie, static_cast(source)); -} - -void PageHost::page_did_update_cookie(Web::Cookie::Cookie cookie) -{ - m_client.async_did_update_cookie(move(cookie)); -} - -void PageHost::page_did_update_resource_count(i32 count_waiting) -{ - m_client.async_did_update_resource_count(count_waiting); -} - -String PageHost::page_did_request_new_tab(Web::HTML::ActivateTab activate_tab) -{ - return m_client.did_request_new_tab(activate_tab); -} - -void PageHost::page_did_request_activate_tab() -{ - m_client.async_did_request_activate_tab(); -} - -void PageHost::page_did_close_browsing_context(Web::HTML::BrowsingContext const&) -{ - m_client.async_did_close_browsing_context(); -} - -void PageHost::request_file(Web::FileRequest file_request) -{ - m_client.request_file(move(file_request)); -} - -void PageHost::page_did_request_color_picker(Color current_color) -{ - m_client.async_did_request_color_picker(current_color); -} - -void PageHost::page_did_change_theme_color(Gfx::Color color) -{ - m_client.async_did_change_theme_color(color); -} - -void PageHost::page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) -{ - m_client.async_did_insert_clipboard_entry(move(data), move(presentation_style), move(mime_type)); -} - -void PageHost::inspector_did_load() -{ - m_client.async_inspector_did_load(); -} - -void PageHost::inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) -{ - m_client.async_inspector_did_select_dom_node(node_id, pseudo_element); -} - } diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h index ddbd6c5f26..0dc3c6bbba 100644 --- a/Userland/Services/WebContent/PageHost.h +++ b/Userland/Services/WebContent/PageHost.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2020-2023, Andreas Kling * Copyright (c) 2021-2023, Linus Groh + * Copyright (c) 2023, Andrew Kaster * * SPDX-License-Identifier: BSD-2-Clause */ @@ -17,7 +18,7 @@ namespace WebContent { class ConnectionFromClient; -class PageHost final : public Web::PageClient { +class PageHost { AK_MAKE_NONCOPYABLE(PageHost); AK_MAKE_NONMOVABLE(PageHost); @@ -25,124 +26,19 @@ public: static NonnullOwnPtr create(ConnectionFromClient& client) { return adopt_own(*new PageHost(client)); } virtual ~PageHost(); - static void set_use_gpu_painter(); - - virtual Web::Page& page() override { return *m_page; } - virtual Web::Page const& page() const override { return *m_page; } - - virtual void paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap&) override; - - void set_palette_impl(Gfx::PaletteImpl&); - void set_viewport_rect(Web::DevicePixelRect const&); - void set_screen_rects(Vector const& rects, size_t main_screen_index) { m_screen_rect = rects[main_screen_index].to_type(); } - void set_device_pixels_per_css_pixel(float device_pixels_per_css_pixel) { m_device_pixels_per_css_pixel = device_pixels_per_css_pixel; } - void set_preferred_color_scheme(Web::CSS::PreferredColorScheme); - void set_should_show_line_box_borders(bool b) { m_should_show_line_box_borders = b; } - void set_has_focus(bool); - void set_is_scripting_enabled(bool); - void set_window_position(Web::DevicePixelPoint); - void set_window_size(Web::DevicePixelSize); - - Web::DevicePixelSize content_size() const { return m_content_size; } - - ErrorOr connect_to_webdriver(DeprecatedString const& webdriver_ipc_path); Function on_webdriver_connection; - void alert_closed(); - void confirm_closed(bool accepted); - void prompt_closed(Optional response); - void color_picker_closed(Optional picked_color); + PageClient& page(u64 index) { return *m_pages.find(index)->value; } + PageClient& create_page(); - Web::WebIDL::ExceptionOr toggle_media_play_state(); - void toggle_media_mute_state(); - Web::WebIDL::ExceptionOr toggle_media_loop_state(); - Web::WebIDL::ExceptionOr toggle_media_controls_state(); - - [[nodiscard]] Gfx::Color background_color() const; - - void set_user_style(String source); + ConnectionFromClient& client() const { return m_client; } private: - // ^PageClient - virtual bool is_connection_open() const override; - virtual Gfx::Palette palette() const override; - virtual Web::DevicePixelRect screen_rect() const override { return m_screen_rect; } - virtual double device_pixels_per_css_pixel() const override { return m_device_pixels_per_css_pixel; } - virtual Web::CSS::PreferredColorScheme preferred_color_scheme() const override { return m_preferred_color_scheme; } - virtual void page_did_invalidate(Web::CSSPixelRect const&) override; - virtual void page_did_change_selection() override; - virtual void page_did_request_cursor_change(Gfx::StandardCursor) override; - virtual void page_did_layout() override; - virtual void page_did_change_title(DeprecatedString const&) override; - virtual void page_did_request_navigate_back() override; - virtual void page_did_request_navigate_forward() override; - virtual void page_did_request_refresh() override; - virtual Gfx::IntSize page_did_request_resize_window(Gfx::IntSize) override; - virtual Gfx::IntPoint page_did_request_reposition_window(Gfx::IntPoint) override; - virtual void page_did_request_restore_window() override; - virtual Gfx::IntRect page_did_request_maximize_window() override; - virtual Gfx::IntRect page_did_request_minimize_window() override; - virtual Gfx::IntRect page_did_request_fullscreen_window() override; - virtual void page_did_request_scroll(i32, i32) override; - virtual void page_did_request_scroll_to(Web::CSSPixelPoint) override; - virtual void page_did_request_scroll_into_view(Web::CSSPixelRect const&) override; - virtual void page_did_enter_tooltip_area(Web::CSSPixelPoint, DeprecatedString const&) override; - virtual void page_did_leave_tooltip_area() override; - virtual void page_did_hover_link(const URL&) override; - virtual void page_did_unhover_link() override; - virtual void page_did_click_link(const URL&, DeprecatedString const& target, unsigned modifiers) override; - virtual void page_did_middle_click_link(const URL&, DeprecatedString const& target, unsigned modifiers) override; - virtual void page_did_request_context_menu(Web::CSSPixelPoint) override; - virtual void page_did_request_link_context_menu(Web::CSSPixelPoint, URL const&, DeprecatedString const& target, unsigned modifiers) override; - virtual void page_did_request_image_context_menu(Web::CSSPixelPoint, const URL&, DeprecatedString const& target, unsigned modifiers, Gfx::Bitmap const*) override; - virtual void page_did_request_media_context_menu(Web::CSSPixelPoint, DeprecatedString const& target, unsigned modifiers, Web::Page::MediaContextMenu) override; - virtual void page_did_start_loading(const URL&, bool) override; - virtual void page_did_create_new_document(Web::DOM::Document&) override; - virtual void page_did_destroy_document(Web::DOM::Document&) override; - virtual void page_did_finish_loading(const URL&) override; - virtual void page_did_request_alert(String const&) override; - virtual void page_did_request_confirm(String const&) override; - virtual void page_did_request_prompt(String const&, String const&) override; - virtual void page_did_request_set_prompt_text(String const&) override; - virtual void page_did_request_accept_dialog() override; - virtual void page_did_request_dismiss_dialog() override; - virtual void page_did_change_favicon(Gfx::Bitmap const&) override; - virtual Vector page_did_request_all_cookies(URL const&) override; - virtual Optional page_did_request_named_cookie(URL const&, DeprecatedString const&) override; - virtual DeprecatedString page_did_request_cookie(const URL&, Web::Cookie::Source) override; - virtual void page_did_set_cookie(const URL&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override; - virtual void page_did_update_cookie(Web::Cookie::Cookie) override; - virtual void page_did_update_resource_count(i32) override; - virtual String page_did_request_new_tab(Web::HTML::ActivateTab activate_tab) override; - virtual void page_did_request_activate_tab() override; - virtual void page_did_close_browsing_context(Web::HTML::BrowsingContext const&) override; - virtual void request_file(Web::FileRequest) override; - virtual void page_did_request_color_picker(Color current_color) override; - virtual void page_did_finish_text_test() override; - virtual void page_did_change_theme_color(Gfx::Color color) override; - virtual void page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) override; - virtual void inspector_did_load() override; - virtual void inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) override; - explicit PageHost(ConnectionFromClient&); - Web::Layout::Viewport* layout_root(); - void setup_palette(); - ConnectionFromClient& m_client; - NonnullOwnPtr m_page; - RefPtr m_palette_impl; - Web::DevicePixelRect m_screen_rect; - Web::DevicePixelSize m_content_size; - float m_device_pixels_per_css_pixel { 1.0f }; - bool m_should_show_line_box_borders { false }; - bool m_has_focus { false }; - - RefPtr m_invalidation_coalescing_timer; - Web::DevicePixelRect m_invalidation_rect; - Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto }; - - RefPtr m_webdriver; + HashMap> m_pages; + u64 m_next_id { 0 }; }; }