1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 08:14:58 +00:00

Ladybird+WebContent: Update IPC calls to handle multiple traversables

The IPC layer between chromes and LibWeb now understands that multiple
top level traversables can live in each WebContent process.

This largely mechanical change adds a billion page_id/page_index
arguments to make sure that pages that end up opening new WebViews
through mechanisms like window.open() still work properly with those
extra windows.
This commit is contained in:
Andrew Kaster 2024-02-02 18:00:48 -07:00 committed by Tim Flynn
parent adb5c27331
commit 36cd2fb7c5
20 changed files with 1542 additions and 969 deletions

View file

@ -8,12 +8,15 @@
#include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SystemTheme.h>
#include <LibJS/Console.h>
#include <LibJS/Runtime/ConsoleObject.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/CSS/SystemColor.h>
#include <LibWeb/Cookie/ParsedCookie.h>
#include <LibWeb/DOM/Attr.h>
#include <LibWeb/DOM/NamedNodeMap.h>
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/Scripting/ClassicScript.h>
#include <LibWeb/HTML/TraversableNavigable.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Painting/PaintableBox.h>
@ -54,20 +57,20 @@ PageClient::PageClient(PageHost& owner, u64 id)
setup_palette();
m_repaint_timer = Web::Platform::Timer::create_single_shot(0, [this] {
if (!client().backing_stores().back_bitmap) {
if (!m_backing_stores.back_bitmap) {
return;
}
auto& back_bitmap = *client().backing_stores().back_bitmap;
auto& back_bitmap = *m_backing_stores.back_bitmap;
auto viewport_rect = page().css_to_device_rect(page().top_level_traversable()->viewport_rect());
paint(viewport_rect, back_bitmap);
auto& backing_stores = client().backing_stores();
auto& backing_stores = m_backing_stores;
swap(backing_stores.front_bitmap, backing_stores.back_bitmap);
swap(backing_stores.front_bitmap_id, backing_stores.back_bitmap_id);
m_paint_state = PaintState::WaitingForClient;
client().async_did_paint(viewport_rect.to_type<int>(), backing_stores.front_bitmap_id);
client().async_did_paint(m_id, viewport_rect.to_type<int>(), backing_stores.front_bitmap_id);
});
#ifdef HAS_ACCELERATED_GRAPHICS
@ -101,6 +104,14 @@ void PageClient::ready_to_paint()
schedule_repaint();
}
void PageClient::add_backing_store(i32 front_bitmap_id, Gfx::ShareableBitmap const& front_bitmap, i32 back_bitmap_id, Gfx::ShareableBitmap const& back_bitmap)
{
m_backing_stores.front_bitmap_id = front_bitmap_id;
m_backing_stores.back_bitmap_id = back_bitmap_id;
m_backing_stores.front_bitmap = *const_cast<Gfx::ShareableBitmap&>(front_bitmap).bitmap();
m_backing_stores.back_bitmap = *const_cast<Gfx::ShareableBitmap&>(back_bitmap).bitmap();
}
void PageClient::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
@ -220,7 +231,7 @@ void PageClient::page_did_invalidate(Web::CSSPixelRect const&)
void PageClient::page_did_request_cursor_change(Gfx::StandardCursor cursor)
{
client().async_did_request_cursor_change((u32)cursor);
client().async_did_request_cursor_change(m_id, (u32)cursor);
}
void PageClient::page_did_layout()
@ -231,62 +242,62 @@ void PageClient::page_did_layout()
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<int>());
client().async_did_layout(m_id, m_content_size.to_type<int>());
}
void PageClient::page_did_change_title(ByteString const& title)
{
client().async_did_change_title(title);
client().async_did_change_title(m_id, title);
}
void PageClient::page_did_request_navigate_back()
{
client().async_did_request_navigate_back();
client().async_did_request_navigate_back(m_id);
}
void PageClient::page_did_request_navigate_forward()
{
client().async_did_request_navigate_forward();
client().async_did_request_navigate_forward(m_id);
}
void PageClient::page_did_request_refresh()
{
client().async_did_request_refresh();
client().async_did_request_refresh(m_id);
}
Gfx::IntSize PageClient::page_did_request_resize_window(Gfx::IntSize size)
{
return client().did_request_resize_window(size);
return client().did_request_resize_window(m_id, size);
}
Gfx::IntPoint PageClient::page_did_request_reposition_window(Gfx::IntPoint position)
{
return client().did_request_reposition_window(position);
return client().did_request_reposition_window(m_id, position);
}
void PageClient::page_did_request_restore_window()
{
client().async_did_request_restore_window();
client().async_did_request_restore_window(m_id);
}
Gfx::IntRect PageClient::page_did_request_maximize_window()
{
return client().did_request_maximize_window();
return client().did_request_maximize_window(m_id);
}
Gfx::IntRect PageClient::page_did_request_minimize_window()
{
return client().did_request_minimize_window();
return client().did_request_minimize_window(m_id);
}
Gfx::IntRect PageClient::page_did_request_fullscreen_window()
{
return client().did_request_fullscreen_window();
return client().did_request_fullscreen_window(m_id);
}
void PageClient::page_did_request_scroll(i32 x_delta, i32 y_delta)
{
client().async_did_request_scroll(x_delta, y_delta);
client().async_did_request_scroll(m_id, x_delta, y_delta);
}
void PageClient::page_did_request_scroll_to(Web::CSSPixelPoint scroll_position)
@ -299,83 +310,83 @@ void PageClient::page_did_request_scroll_to(Web::CSSPixelPoint scroll_position)
page().top_level_traversable()->set_viewport_rect(viewport);
auto device_scroll_position = page().css_to_device_point(scroll_position);
client().async_did_request_scroll_to(device_scroll_position.to_type<int>());
client().async_did_request_scroll_to(m_id, device_scroll_position.to_type<int>());
}
void PageClient::page_did_enter_tooltip_area(Web::CSSPixelPoint content_position, ByteString const& title)
{
client().async_did_enter_tooltip_area({ content_position.x().to_int(), content_position.y().to_int() }, title);
client().async_did_enter_tooltip_area(m_id, { content_position.x().to_int(), content_position.y().to_int() }, title);
}
void PageClient::page_did_leave_tooltip_area()
{
client().async_did_leave_tooltip_area();
client().async_did_leave_tooltip_area(m_id);
}
void PageClient::page_did_hover_link(const URL& url)
{
client().async_did_hover_link(url);
client().async_did_hover_link(m_id, url);
}
void PageClient::page_did_unhover_link()
{
client().async_did_unhover_link();
client().async_did_unhover_link(m_id);
}
void PageClient::page_did_middle_click_link(const URL& url, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers)
{
client().async_did_middle_click_link(url, target, modifiers);
client().async_did_middle_click_link(m_id, url, target, modifiers);
}
void PageClient::page_did_start_loading(const URL& url, bool is_redirect)
{
client().async_did_start_loading(url, is_redirect);
client().async_did_start_loading(m_id, url, is_redirect);
}
void PageClient::page_did_create_new_document(Web::DOM::Document& document)
{
client().initialize_js_console({}, document);
initialize_js_console(document);
}
void PageClient::page_did_destroy_document(Web::DOM::Document& document)
{
client().destroy_js_console({}, document);
destroy_js_console(document);
}
void PageClient::page_did_finish_loading(const URL& url)
{
client().async_did_finish_loading(url);
client().async_did_finish_loading(m_id, url);
}
void PageClient::page_did_finish_text_test()
{
client().async_did_finish_text_test();
client().async_did_finish_text_test(m_id);
}
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<int>());
client().async_did_request_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>());
}
void PageClient::page_did_request_link_context_menu(Web::CSSPixelPoint content_position, URL const& url, ByteString const& target, unsigned modifiers)
{
client().async_did_request_link_context_menu(page().css_to_device_point(content_position).to_type<int>(), url, target, modifiers);
client().async_did_request_link_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>(), url, target, modifiers);
}
void PageClient::page_did_request_image_context_menu(Web::CSSPixelPoint content_position, URL const& url, ByteString 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<int>(), url, target, modifiers, bitmap);
client().async_did_request_image_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>(), url, target, modifiers, bitmap);
}
void PageClient::page_did_request_media_context_menu(Web::CSSPixelPoint content_position, ByteString const& target, unsigned modifiers, Web::Page::MediaContextMenu menu)
{
client().async_did_request_media_context_menu(page().css_to_device_point(content_position).to_type<int>(), target, modifiers, move(menu));
client().async_did_request_media_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>(), target, modifiers, move(menu));
}
void PageClient::page_did_request_alert(String const& message)
{
client().async_did_request_alert(message);
client().async_did_request_alert(m_id, message);
}
void PageClient::alert_closed()
@ -385,7 +396,7 @@ void PageClient::alert_closed()
void PageClient::page_did_request_confirm(String const& message)
{
client().async_did_request_confirm(message);
client().async_did_request_confirm(m_id, message);
}
void PageClient::confirm_closed(bool accepted)
@ -395,12 +406,12 @@ void PageClient::confirm_closed(bool accepted)
void PageClient::page_did_request_prompt(String const& message, String const& default_)
{
client().async_did_request_prompt(message, default_);
client().async_did_request_prompt(m_id, message, default_);
}
void PageClient::page_did_request_set_prompt_text(String const& text)
{
client().async_did_request_set_prompt_text(text);
client().async_did_request_set_prompt_text(m_id, text);
}
void PageClient::prompt_closed(Optional<String> response)
@ -445,32 +456,32 @@ void PageClient::set_user_style(String source)
void PageClient::page_did_request_accept_dialog()
{
client().async_did_request_accept_dialog();
client().async_did_request_accept_dialog(m_id);
}
void PageClient::page_did_request_dismiss_dialog()
{
client().async_did_request_dismiss_dialog();
client().async_did_request_dismiss_dialog(m_id);
}
void PageClient::page_did_change_favicon(Gfx::Bitmap const& favicon)
{
client().async_did_change_favicon(favicon.to_shareable_bitmap());
client().async_did_change_favicon(m_id, favicon.to_shareable_bitmap());
}
Vector<Web::Cookie::Cookie> PageClient::page_did_request_all_cookies(URL const& url)
{
return client().did_request_all_cookies(url);
return client().did_request_all_cookies(m_id, url);
}
Optional<Web::Cookie::Cookie> PageClient::page_did_request_named_cookie(URL const& url, String const& name)
{
return client().did_request_named_cookie(url, name);
return client().did_request_named_cookie(m_id, url, name);
}
String PageClient::page_did_request_cookie(const URL& url, Web::Cookie::Source source)
{
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidRequestCookie>(move(url), source);
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidRequestCookie>(m_id, move(url), source);
if (!response) {
dbgln("WebContent client disconnected during DidRequestCookie. Exiting peacefully.");
exit(0);
@ -480,7 +491,7 @@ String PageClient::page_did_request_cookie(const URL& url, Web::Cookie::Source s
void PageClient::page_did_set_cookie(const URL& url, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source)
{
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidSetCookie>(url, cookie, source);
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidSetCookie>(m_id, url, cookie, source);
if (!response) {
dbgln("WebContent client disconnected during DidSetCookie. Exiting peacefully.");
exit(0);
@ -489,12 +500,12 @@ void PageClient::page_did_set_cookie(const URL& url, Web::Cookie::ParsedCookie c
void PageClient::page_did_update_cookie(Web::Cookie::Cookie cookie)
{
client().async_did_update_cookie(move(cookie));
client().async_did_update_cookie(m_id, move(cookie));
}
void PageClient::page_did_update_resource_count(i32 count_waiting)
{
client().async_did_update_resource_count(count_waiting);
client().async_did_update_resource_count(m_id, count_waiting);
}
PageClient::NewWebViewResult PageClient::page_did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Web::HTML::TokenizedFeature::NoOpener no_opener)
@ -509,7 +520,7 @@ PageClient::NewWebViewResult PageClient::page_did_request_new_web_view(Web::HTML
page_id = new_client.m_id;
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidRequestNewWebView>(activate_tab, hints, page_id);
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidRequestNewWebView>(m_id, activate_tab, hints, page_id);
if (!response) {
dbgln("WebContent client disconnected during DidRequestNewWebView. Exiting peacefully.");
exit(0);
@ -520,42 +531,47 @@ PageClient::NewWebViewResult PageClient::page_did_request_new_web_view(Web::HTML
void PageClient::page_did_request_activate_tab()
{
client().async_did_request_activate_tab();
client().async_did_request_activate_tab(m_id);
}
void PageClient::page_did_close_browsing_context(Web::HTML::BrowsingContext const&)
void PageClient::page_did_close_top_level_traversable()
{
client().async_did_close_browsing_context();
// FIXME: Rename this IPC call
client().async_did_close_browsing_context(m_id);
// NOTE: This only removes the strong reference the PageHost has for this PageClient.
// It will be GC'd 'later'.
m_owner.remove_page({}, m_id);
}
void PageClient::request_file(Web::FileRequest file_request)
{
client().request_file(move(file_request));
client().request_file(m_id, move(file_request));
}
void PageClient::page_did_request_color_picker(Color current_color)
{
client().async_did_request_color_picker(current_color);
client().async_did_request_color_picker(m_id, current_color);
}
void PageClient::page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items)
{
client().async_did_request_select_dropdown(page().css_to_device_point(content_position).to_type<int>(), minimum_width * device_pixels_per_css_pixel(), items);
client().async_did_request_select_dropdown(m_id, page().css_to_device_point(content_position).to_type<int>(), minimum_width * device_pixels_per_css_pixel(), items);
}
void PageClient::page_did_change_theme_color(Gfx::Color color)
{
client().async_did_change_theme_color(color);
client().async_did_change_theme_color(m_id, 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));
client().async_did_insert_clipboard_entry(m_id, move(data), move(presentation_style), move(mime_type));
}
WebView::SocketPair PageClient::request_worker_agent()
{
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::RequestWorkerAgent>();
auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::RequestWorkerAgent>(m_id);
if (!response) {
dbgln("WebContent client disconnected during RequestWorkerAgent. Exiting peacefully.");
exit(0);
@ -566,22 +582,22 @@ WebView::SocketPair PageClient::request_worker_agent()
void PageClient::inspector_did_load()
{
client().async_inspector_did_load();
client().async_inspector_did_load(m_id);
}
void PageClient::inspector_did_select_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element)
{
client().async_inspector_did_select_dom_node(node_id, pseudo_element);
client().async_inspector_did_select_dom_node(m_id, node_id, pseudo_element);
}
void PageClient::inspector_did_set_dom_node_text(i32 node_id, String const& text)
{
client().async_inspector_did_set_dom_node_text(node_id, text);
client().async_inspector_did_set_dom_node_text(m_id, node_id, text);
}
void PageClient::inspector_did_set_dom_node_tag(i32 node_id, String const& tag)
{
client().async_inspector_did_set_dom_node_tag(node_id, tag);
client().async_inspector_did_set_dom_node_tag(m_id, node_id, tag);
}
static Vector<WebView::Attribute> named_node_map_to_vector(JS::NonnullGCPtr<Web::DOM::NamedNodeMap> map)
@ -601,12 +617,12 @@ static Vector<WebView::Attribute> named_node_map_to_vector(JS::NonnullGCPtr<Web:
void PageClient::inspector_did_add_dom_node_attributes(i32 node_id, JS::NonnullGCPtr<Web::DOM::NamedNodeMap> attributes)
{
client().async_inspector_did_add_dom_node_attributes(node_id, named_node_map_to_vector(attributes));
client().async_inspector_did_add_dom_node_attributes(m_id, node_id, named_node_map_to_vector(attributes));
}
void PageClient::inspector_did_replace_dom_node_attribute(i32 node_id, String const& name, JS::NonnullGCPtr<Web::DOM::NamedNodeMap> replacement_attributes)
{
client().async_inspector_did_replace_dom_node_attribute(node_id, name, named_node_map_to_vector(replacement_attributes));
client().async_inspector_did_replace_dom_node_attribute(m_id, node_id, name, named_node_map_to_vector(replacement_attributes));
}
void PageClient::inspector_did_request_dom_tree_context_menu(i32 node_id, Web::CSSPixelPoint position, String const& type, Optional<String> const& tag, Optional<String> const& attribute_name, Optional<String> const& attribute_value)
@ -615,12 +631,12 @@ void PageClient::inspector_did_request_dom_tree_context_menu(i32 node_id, Web::C
if (attribute_name.has_value() && attribute_value.has_value())
attribute = WebView::Attribute { *attribute_name, *attribute_value };
client().async_inspector_did_request_dom_tree_context_menu(node_id, page().css_to_device_point(position).to_type<int>(), type, tag, move(attribute));
client().async_inspector_did_request_dom_tree_context_menu(m_id, node_id, page().css_to_device_point(position).to_type<int>(), type, tag, move(attribute));
}
void PageClient::inspector_did_execute_console_script(String const& script)
{
client().async_inspector_did_execute_console_script(script);
client().async_inspector_did_execute_console_script(m_id, script);
}
ErrorOr<void> PageClient::connect_to_webdriver(ByteString const& webdriver_ipc_path)
@ -634,4 +650,78 @@ ErrorOr<void> PageClient::connect_to_webdriver(ByteString const& webdriver_ipc_p
return {};
}
void PageClient::initialize_js_console(Web::DOM::Document& document)
{
auto& realm = document.realm();
auto console_object = realm.intrinsics().console_object();
auto console_client = make<WebContentConsoleClient>(console_object->console(), document.realm(), *this);
console_object->console().set_client(*console_client);
VERIFY(document.browsing_context());
if (document.browsing_context()->is_top_level()) {
m_top_level_document_console_client = console_client->make_weak_ptr();
}
m_console_clients.set(&document, move(console_client));
}
void PageClient::destroy_js_console(Web::DOM::Document& document)
{
m_console_clients.remove(&document);
}
void PageClient::js_console_input(ByteString const& js_source)
{
if (m_top_level_document_console_client)
m_top_level_document_console_client->handle_input(js_source);
}
void PageClient::run_javascript(ByteString const& js_source)
{
auto* active_document = page().top_level_browsing_context().active_document();
if (!active_document)
return;
// This is partially based on "execute a javascript: URL request" https://html.spec.whatwg.org/multipage/browsing-the-web.html#javascript-protocol
// Let settings be browsingContext's active document's relevant settings object.
auto& settings = active_document->relevant_settings_object();
// Let baseURL be settings's API base URL.
auto base_url = settings.api_base_url();
// Let script be the result of creating a classic script given scriptSource, settings, baseURL, and the default classic script fetch options.
// FIXME: This doesn't pass in "default classic script fetch options"
// FIXME: What should the filename be here?
auto script = Web::HTML::ClassicScript::create("(client connection run_javascript)", js_source, settings, move(base_url));
// Let evaluationStatus be the result of running the classic script script.
auto evaluation_status = script->run();
if (evaluation_status.is_error())
dbgln("Exception :(");
}
void PageClient::js_console_request_messages(i32 start_index)
{
if (m_top_level_document_console_client)
m_top_level_document_console_client->send_messages(start_index);
}
void PageClient::did_output_js_console_message(i32 message_index)
{
client().async_did_output_js_console_message(m_id, message_index);
}
void PageClient::console_peer_did_misbehave(char const* reason)
{
client().did_misbehave(reason);
}
void PageClient::did_get_js_console_messages(i32 start_index, Vector<ByteString> message_types, Vector<ByteString> messages)
{
client().async_did_get_js_console_messages(m_id, start_index, move(message_types), move(messages));
}
}