diff --git a/Ladybird/Headless/Application.cpp b/Ladybird/Headless/Application.cpp index ee209adbdf9..cb89647a2fd 100644 --- a/Ladybird/Headless/Application.cpp +++ b/Ladybird/Headless/Application.cpp @@ -68,12 +68,20 @@ ErrorOr Application::launch_services() return {}; } -ErrorOr Application::create_web_view(Core::AnonymousBuffer theme, Gfx::IntSize window_size) +HeadlessWebView& Application::create_web_view(Core::AnonymousBuffer theme, Gfx::IntSize window_size) { - auto web_view = TRY(HeadlessWebView::create(move(theme), window_size)); + auto web_view = HeadlessWebView::create(move(theme), window_size); m_web_views.append(move(web_view)); - return m_web_views.last().ptr(); + return *m_web_views.last(); +} + +HeadlessWebView& Application::create_child_web_view(HeadlessWebView const& parent, u64 page_index) +{ + auto web_view = HeadlessWebView::create_child(parent, page_index); + m_web_views.append(move(web_view)); + + return *m_web_views.last(); } void Application::destroy_web_views() diff --git a/Ladybird/Headless/Application.h b/Ladybird/Headless/Application.h index 8027f122426..38e61fcd2ea 100644 --- a/Ladybird/Headless/Application.h +++ b/Ladybird/Headless/Application.h @@ -37,7 +37,8 @@ public: static Requests::RequestClient& request_client() { return *the().m_request_client; } static ImageDecoderClient::Client& image_decoder_client() { return *the().m_image_decoder_client; } - ErrorOr create_web_view(Core::AnonymousBuffer theme, Gfx::IntSize window_size); + HeadlessWebView& create_web_view(Core::AnonymousBuffer theme, Gfx::IntSize window_size); + HeadlessWebView& create_child_web_view(HeadlessWebView const&, u64 page_index); void destroy_web_views(); template diff --git a/Ladybird/Headless/HeadlessWebView.cpp b/Ladybird/Headless/HeadlessWebView.cpp index 9b057df3190..7ed43ba5c2b 100644 --- a/Ladybird/Headless/HeadlessWebView.cpp +++ b/Ladybird/Headless/HeadlessWebView.cpp @@ -10,13 +10,25 @@ #include #include #include +#include namespace Ladybird { -HeadlessWebView::HeadlessWebView(Gfx::IntSize viewport_size) - : m_viewport_size(viewport_size) +HeadlessWebView::HeadlessWebView(Core::AnonymousBuffer theme, Gfx::IntSize viewport_size) + : m_theme(move(theme)) + , m_viewport_size(viewport_size) , m_test_promise(TestPromise::construct()) { + on_new_web_view = [this](auto, auto, Optional page_index) { + if (page_index.has_value()) { + auto& web_view = Application::the().create_child_web_view(*this, *page_index); + return web_view.handle(); + } + + auto& web_view = Application::the().create_web_view(m_theme, m_viewport_size); + return web_view.handle(); + }; + on_request_worker_agent = []() { auto web_worker_paths = MUST(get_paths_for_helper_process("WebWorker"sv)); auto worker_client = MUST(launch_web_worker_process(web_worker_paths, Application::request_client())); @@ -25,38 +37,60 @@ HeadlessWebView::HeadlessWebView(Gfx::IntSize viewport_size) }; } -ErrorOr> HeadlessWebView::create(Core::AnonymousBuffer theme, Gfx::IntSize window_size) +NonnullOwnPtr HeadlessWebView::create(Core::AnonymousBuffer theme, Gfx::IntSize window_size) { - auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebView(window_size))); - - auto request_server_socket = TRY(connect_new_request_server_client(Application::request_client())); - auto image_decoder_socket = TRY(connect_new_image_decoder_client(Application::image_decoder_client())); - - auto candidate_web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv)); - view->m_client_state.client = TRY(launch_web_content_process(*view, candidate_web_content_paths, move(image_decoder_socket), move(request_server_socket))); - - view->client().async_update_system_theme(0, move(theme)); - view->client().async_set_viewport_size(0, view->viewport_size()); - view->client().async_set_window_size(0, view->viewport_size()); - - if (WebView::Application::chrome_options().allow_popups == WebView::AllowPopups::Yes) - view->client().async_debug_request(0, "block-pop-ups"sv, "off"sv); - - if (auto web_driver_ipc_path = WebView::Application::chrome_options().webdriver_content_ipc_path; web_driver_ipc_path.has_value()) - view->client().async_connect_to_webdriver(0, *web_driver_ipc_path); - - view->m_client_state.client->on_web_content_process_crash = [&view = *view] { - warnln("\033[31;1mWebContent Crashed!!\033[0m"); - warnln(" Last page loaded: {}", view.url()); - VERIFY_NOT_REACHED(); - }; + auto view = adopt_own(*new HeadlessWebView(move(theme), window_size)); + view->initialize_client(CreateNewClient::Yes); return view; } +NonnullOwnPtr HeadlessWebView::create_child(HeadlessWebView const& parent, u64 page_index) +{ + auto view = adopt_own(*new HeadlessWebView(parent.m_theme, parent.m_viewport_size)); + + view->m_client_state.client = parent.client(); + view->m_client_state.page_index = page_index; + view->initialize_client(CreateNewClient::No); + + return view; +} + +void HeadlessWebView::initialize_client(CreateNewClient create_new_client) +{ + if (create_new_client == CreateNewClient::Yes) { + auto request_server_socket = connect_new_request_server_client(Application::request_client()).release_value_but_fixme_should_propagate_errors(); + auto image_decoder_socket = connect_new_image_decoder_client(Application::image_decoder_client()).release_value_but_fixme_should_propagate_errors(); + + auto web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors(); + m_client_state.client = launch_web_content_process(*this, web_content_paths, move(image_decoder_socket), move(request_server_socket)).release_value_but_fixme_should_propagate_errors(); + } else { + m_client_state.client->register_view(m_client_state.page_index, *this); + } + + m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid()); + client().async_set_window_handle(m_client_state.page_index, m_client_state.client_handle); + + client().async_update_system_theme(m_client_state.page_index, m_theme); + client().async_set_viewport_size(m_client_state.page_index, viewport_size()); + client().async_set_window_size(m_client_state.page_index, viewport_size()); + + if (Application::chrome_options().allow_popups == WebView::AllowPopups::Yes) + client().async_debug_request(m_client_state.page_index, "block-pop-ups"sv, "off"sv); + + if (auto const& web_driver_ipc_path = Application::chrome_options().webdriver_content_ipc_path; web_driver_ipc_path.has_value()) + client().async_connect_to_webdriver(m_client_state.page_index, *web_driver_ipc_path); + + m_client_state.client->on_web_content_process_crash = [this] { + warnln("\033[31;1mWebContent Crashed!!\033[0m"); + warnln(" Last page loaded: {}", url()); + VERIFY_NOT_REACHED(); + }; +} + void HeadlessWebView::clear_content_filters() { - client().async_set_content_filters(0, {}); + client().async_set_content_filters(m_client_state.page_index, {}); } NonnullRefPtr>> HeadlessWebView::take_screenshot() diff --git a/Ladybird/Headless/HeadlessWebView.h b/Ladybird/Headless/HeadlessWebView.h index 1f1c806471c..e7d2b8e96d1 100644 --- a/Ladybird/Headless/HeadlessWebView.h +++ b/Ladybird/Headless/HeadlessWebView.h @@ -20,7 +20,8 @@ namespace Ladybird { class HeadlessWebView final : public WebView::ViewImplementation { public: - static ErrorOr> create(Core::AnonymousBuffer theme, Gfx::IntSize window_size); + static NonnullOwnPtr create(Core::AnonymousBuffer theme, Gfx::IntSize window_size); + static NonnullOwnPtr create_child(HeadlessWebView const&, u64 page_index); void clear_content_filters(); @@ -30,10 +31,10 @@ public: void on_test_complete(TestCompletion); private: - explicit HeadlessWebView(Gfx::IntSize viewport_size); + HeadlessWebView(Core::AnonymousBuffer theme, Gfx::IntSize viewport_size); void update_zoom() override { } - void initialize_client(CreateNewClient) override { } + void initialize_client(CreateNewClient) override; virtual Web::DevicePixelSize viewport_size() const override { return m_viewport_size.to_type(); } virtual Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const override { return widget_position; } @@ -41,7 +42,9 @@ private: virtual void did_receive_screenshot(Badge, Gfx::ShareableBitmap const& screenshot) override; + Core::AnonymousBuffer m_theme; Gfx::IntSize m_viewport_size; + RefPtr>> m_pending_screenshot; NonnullRefPtr m_test_promise; diff --git a/Ladybird/Headless/Test.cpp b/Ladybird/Headless/Test.cpp index 93d4713b7bb..ef645de0b87 100644 --- a/Ladybird/Headless/Test.cpp +++ b/Ladybird/Headless/Test.cpp @@ -402,7 +402,7 @@ ErrorOr run_tests(Core::AnonymousBuffer const& theme, Gfx::IntSize window_ size_t loaded_web_views = 0; for (size_t i = 0; i < concurrency; ++i) { - auto& view = *TRY(app.create_web_view(theme, window_size)); + auto& view = app.create_web_view(theme, window_size); view.on_load_finish = [&](auto const&) { ++loaded_web_views; }; } diff --git a/Ladybird/Headless/main.cpp b/Ladybird/Headless/main.cpp index 4506d80fe02..feb022662ed 100644 --- a/Ladybird/Headless/main.cpp +++ b/Ladybird/Headless/main.cpp @@ -81,7 +81,7 @@ ErrorOr serenity_main(Main::Arguments arguments) return 0; } - auto& view = *TRY(app->create_web_view(move(theme), window_size)); + auto& view = app->create_web_view(move(theme), window_size); VERIFY(!WebView::Application::chrome_options().urls.is_empty()); auto const& url = WebView::Application::chrome_options().urls.first();