diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index 23d5a65205f..4ebda1e5d01 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -1007,26 +1007,26 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ m_web_view_bridge->on_reposition_window = [weak_self](auto position) { LadybirdWebView* self = weak_self; if (self == nil) { - return Gfx::IntPoint {}; + return; } position = Ladybird::compute_origin_relative_to_window([self window], position); [[self window] setFrameOrigin:Ladybird::gfx_point_to_ns_point(position)]; - position = Ladybird::ns_point_to_gfx_point([[self window] frame].origin); - return Ladybird::compute_origin_relative_to_window([self window], position); + m_web_view_bridge->did_update_window_rect(); }; m_web_view_bridge->on_resize_window = [weak_self](auto size) { LadybirdWebView* self = weak_self; if (self == nil) { - return Gfx::IntSize {}; + return; } + auto frame = [[self window] frame]; frame.size = Ladybird::gfx_size_to_ns_size(size); [[self window] setFrame:frame display:YES]; - return Ladybird::ns_size_to_gfx_size([[self window] frame].size); + m_web_view_bridge->did_update_window_rect(); }; m_web_view_bridge->on_maximize_window = [weak_self]() { diff --git a/Ladybird/Qt/Tab.cpp b/Ladybird/Qt/Tab.cpp index b1231f93e0a..44449ecd148 100644 --- a/Ladybird/Qt/Tab.cpp +++ b/Ladybird/Qt/Tab.cpp @@ -354,12 +354,12 @@ Tab::Tab(BrowserWindow* window, RefPtr parent_client, view().on_reposition_window = [this](auto const& position) { m_window->move(position.x(), position.y()); - return Gfx::IntPoint { m_window->x(), m_window->y() }; + view().did_update_window_rect(); }; view().on_resize_window = [this](auto const& size) { m_window->resize(size.width(), size.height()); - return Gfx::IntSize { m_window->width(), m_window->height() }; + view().did_update_window_rect(); }; view().on_maximize_window = [this]() { diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index 439619d0641..36f2abcbcc0 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -48,6 +48,7 @@ void Page::visit_edges(JS::Cell::Visitor& visitor) Base::visit_edges(visitor); visitor.visit(m_top_level_traversable); visitor.visit(m_client); + visitor.visit(m_window_rect_observer); visitor.visit(m_on_pending_dialog_closed); } @@ -254,6 +255,12 @@ JS::NonnullGCPtr Page::top_level_traversable() const return *m_top_level_traversable; } +void Page::did_update_window_rect() +{ + if (m_window_rect_observer) + m_window_rect_observer->function()({ window_position(), window_size() }); +} + template static ResponseType spin_event_loop_until_dialog_closed(PageClient& client, Optional& response, SourceLocation location = SourceLocation::current()) { diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index 028bfee9d2d..3b7a83b8e64 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -127,6 +127,9 @@ public: DevicePixelSize window_size() const { return m_window_size; } void set_window_size(DevicePixelSize size) { m_window_size = size; } + void did_update_window_rect(); + void set_window_rect_observer(JS::GCPtr> window_rect_observer) { m_window_rect_observer = window_rect_observer; } + void did_request_alert(String const& message); void alert_closed(); @@ -245,6 +248,7 @@ private: DevicePixelPoint m_window_position {}; DevicePixelSize m_window_size {}; + JS::GCPtr> m_window_rect_observer; PendingDialog m_pending_dialog { PendingDialog::None }; Optional m_pending_dialog_text; @@ -310,8 +314,8 @@ public: virtual void page_did_request_navigate_back() { } virtual void page_did_request_navigate_forward() { } virtual void page_did_request_refresh() { } - virtual Gfx::IntSize page_did_request_resize_window(Gfx::IntSize) { return {}; } - virtual Gfx::IntPoint page_did_request_reposition_window(Gfx::IntPoint) { return {}; } + virtual void page_did_request_resize_window(Gfx::IntSize) { } + virtual void page_did_request_reposition_window(Gfx::IntPoint) { } virtual void page_did_request_restore_window() { } virtual Gfx::IntRect page_did_request_maximize_window() { return {}; } virtual Gfx::IntRect page_did_request_minimize_window() { return {}; } diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index 90a8635aef3..adc2616bd98 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -87,6 +87,11 @@ void ViewImplementation::set_window_size(Gfx::IntSize size) client().async_set_window_size(m_client_state.page_index, size.to_type()); } +void ViewImplementation::did_update_window_rect() +{ + client().async_did_update_window_rect(m_client_state.page_index); +} + void ViewImplementation::load(URL::URL const& url) { m_url = url; diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 0087a3e78e5..597bd36be3a 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -52,6 +52,7 @@ public: void set_window_position(Gfx::IntPoint); void set_window_size(Gfx::IntSize); + void did_update_window_rect(); void load(URL::URL const&); void load_html(StringView); @@ -202,8 +203,8 @@ public: Function const& message_types, Vector const& messages)> on_received_console_messages; Function on_resource_status_change; Function on_restore_window; - Function on_reposition_window; - Function on_resize_window; + Function on_reposition_window; + Function on_resize_window; Function on_maximize_window; Function on_minimize_window; Function on_fullscreen_window; diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index b447a074804..55bee592290 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -492,24 +492,20 @@ void WebContentClient::did_request_restore_window(u64 page_id) } } -Messages::WebContentClient::DidRequestRepositionWindowResponse WebContentClient::did_request_reposition_window(u64 page_id, Gfx::IntPoint position) +void WebContentClient::did_request_reposition_window(u64 page_id, Gfx::IntPoint position) { if (auto view = view_for_page_id(page_id); view.has_value()) { if (view->on_reposition_window) - return view->on_reposition_window(position); + view->on_reposition_window(position); } - - return Gfx::IntPoint {}; } -Messages::WebContentClient::DidRequestResizeWindowResponse WebContentClient::did_request_resize_window(u64 page_id, Gfx::IntSize size) +void WebContentClient::did_request_resize_window(u64 page_id, Gfx::IntSize size) { if (auto view = view_for_page_id(page_id); view.has_value()) { if (view->on_resize_window) - return view->on_resize_window(size); + view->on_resize_window(size); } - - return Gfx::IntSize {}; } Messages::WebContentClient::DidRequestMaximizeWindowResponse WebContentClient::did_request_maximize_window(u64 page_id) diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index bb101687446..afd041a0e6c 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -100,8 +100,8 @@ private: virtual void did_close_browsing_context(u64 page_id) override; virtual void did_update_resource_count(u64 page_id, i32 count_waiting) override; virtual void did_request_restore_window(u64 page_id) override; - virtual Messages::WebContentClient::DidRequestRepositionWindowResponse did_request_reposition_window(u64 page_id, Gfx::IntPoint) override; - virtual Messages::WebContentClient::DidRequestResizeWindowResponse did_request_resize_window(u64 page_id, Gfx::IntSize) override; + virtual void did_request_reposition_window(u64 page_id, Gfx::IntPoint) override; + virtual void did_request_resize_window(u64 page_id, Gfx::IntSize) override; virtual Messages::WebContentClient::DidRequestMaximizeWindowResponse did_request_maximize_window(u64 page_id) override; virtual Messages::WebContentClient::DidRequestMinimizeWindowResponse did_request_minimize_window(u64 page_id) override; virtual Messages::WebContentClient::DidRequestFullscreenWindowResponse did_request_fullscreen_window(u64 page_id) override; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 20731ad16de..de4182a3f2a 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -1082,6 +1082,12 @@ void ConnectionFromClient::set_window_size(u64 page_id, Web::DevicePixelSize siz page->set_window_size(size); } +void ConnectionFromClient::did_update_window_rect(u64 page_id) +{ + if (auto page = this->page(page_id); page.has_value()) + page->page().did_update_window_rect(); +} + Messages::WebContentServer::GetLocalStorageEntriesResponse ConnectionFromClient::get_local_storage_entries(u64 page_id) { auto page = this->page(page_id); diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index 9b00c77ac30..636cda62cbf 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -103,6 +103,7 @@ private: virtual void set_device_pixels_per_css_pixel(u64 page_id, float) override; virtual void set_window_position(u64 page_id, Web::DevicePixelPoint) override; virtual void set_window_size(u64 page_id, Web::DevicePixelSize) override; + virtual void did_update_window_rect(u64 page_id) override; virtual void handle_file_return(u64 page_id, i32 error, Optional const& file, i32 request_id) override; virtual void set_system_visibility_state(u64 page_id, bool visible) override; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index b3af662a03a..33050caf00d 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -261,14 +261,14 @@ void PageClient::page_did_request_refresh() client().async_did_request_refresh(m_id); } -Gfx::IntSize PageClient::page_did_request_resize_window(Gfx::IntSize size) +void PageClient::page_did_request_resize_window(Gfx::IntSize size) { - return client().did_request_resize_window(m_id, size); + client().async_did_request_resize_window(m_id, size); } -Gfx::IntPoint PageClient::page_did_request_reposition_window(Gfx::IntPoint position) +void PageClient::page_did_request_reposition_window(Gfx::IntPoint position) { - return client().did_request_reposition_window(m_id, position); + client().async_did_request_reposition_window(m_id, position); } void PageClient::page_did_request_restore_window() diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h index 8f6fe57b560..c7a0e690767 100644 --- a/Userland/Services/WebContent/PageClient.h +++ b/Userland/Services/WebContent/PageClient.h @@ -112,8 +112,8 @@ private: 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_resize_window(Gfx::IntSize) override; + virtual void 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; diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index 30b524c7397..c6dfe526eeb 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -77,8 +77,8 @@ endpoint WebContentClient did_request_activate_tab(u64 page_id) =| did_close_browsing_context(u64 page_id) =| did_request_restore_window(u64 page_id) =| - did_request_reposition_window(u64 page_id, Gfx::IntPoint position) => (Gfx::IntPoint window_position) - did_request_resize_window(u64 page_id, Gfx::IntSize size) => (Gfx::IntSize window_size) + did_request_reposition_window(u64 page_id, Gfx::IntPoint position) =| + did_request_resize_window(u64 page_id, Gfx::IntSize size) =| did_request_maximize_window(u64 page_id) => (Gfx::IntRect window_rect) did_request_minimize_window(u64 page_id) => (Gfx::IntRect window_rect) did_request_fullscreen_window(u64 page_id) => (Gfx::IntRect window_rect) diff --git a/Userland/Services/WebContent/WebContentServer.ipc b/Userland/Services/WebContent/WebContentServer.ipc index cf20b215104..b166e95bbf1 100644 --- a/Userland/Services/WebContent/WebContentServer.ipc +++ b/Userland/Services/WebContent/WebContentServer.ipc @@ -90,6 +90,7 @@ endpoint WebContentServer set_window_position(u64 page_id, Web::DevicePixelPoint position) =| set_window_size(u64 page_id, Web::DevicePixelSize size) =| + did_update_window_rect(u64 page_id) =| get_local_storage_entries(u64 page_id) => (OrderedHashMap entries) get_session_storage_entries(u64 page_id) => (OrderedHashMap entries) diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index 9e7287f221d..c24cdcd2e6a 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -647,10 +647,11 @@ Messages::WebDriverClient::SetWindowRectResponse WebDriverConnection::set_window auto const& properties = payload.as_object(); - auto resolve_property = [](auto name, auto const& property, i32 min, i32 max) -> ErrorOr, Web::WebDriver::Error> { + auto resolve_property = [](auto name, auto const& property, double min, double max) -> ErrorOr, Web::WebDriver::Error> { if (property.is_null()) - return Optional {}; - auto value = property.template get_integer(); + return OptionalNone {}; + + auto value = property.get_double_with_precision_loss(); if (!value.has_value()) return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::InvalidArgument, ByteString::formatted("Property '{}' is not a Number", name)); if (*value < min) @@ -694,29 +695,28 @@ Messages::WebDriverClient::SetWindowRectResponse WebDriverConnection::set_window // 11. Restore the window. restore_the_window(); - Gfx::IntRect window_rect; + auto& page = current_top_level_browsing_context()->page(); // 11. If width and height are not null: if (width.has_value() && height.has_value()) { // a. Set the width, in CSS pixels, of the operating system window containing the current top-level browsing context, including any browser chrome and externally drawn window decorations to a value that is as close as possible to width. // b. Set the height, in CSS pixels, of the operating system window containing the current top-level browsing context, including any browser chrome and externally drawn window decorations to a value that is as close as possible to height. - auto size = current_top_level_browsing_context()->page().client().page_did_request_resize_window({ *width, *height }); - window_rect.set_size(size); - } else { - window_rect.set_size(current_top_level_browsing_context()->page().window_size().to_type()); + page.client().page_did_request_resize_window({ *width, *height }); + ++m_pending_window_rect_requests; } // 12. If x and y are not null: if (x.has_value() && y.has_value()) { // a. Run the implementation-specific steps to set the position of the operating system level window containing the current top-level browsing context to the position given by the x and y coordinates. - auto position = current_top_level_browsing_context()->page().client().page_did_request_reposition_window({ *x, *y }); - window_rect.set_location(position); - } else { - window_rect.set_location(current_top_level_browsing_context()->page().window_position().to_type()); + page.client().page_did_request_reposition_window({ *x, *y }); + ++m_pending_window_rect_requests; } + if (m_pending_window_rect_requests == 0) + async_window_rect_updated(serialize_rect(compute_window_rect(page))); + // 14. Return success with data set to the WindowRect object for the current top-level browsing context. - return serialize_rect(window_rect); + return JsonValue {}; } // 11.8.3 Maximize Window, https://w3c.github.io/webdriver/#dfn-maximize-window @@ -2340,9 +2340,19 @@ void WebDriverConnection::set_current_top_level_browsing_context(Web::HTML::Brow // 1. Assert: context is a top-level browsing context. VERIFY(browsing_context.is_top_level()); + if (m_current_top_level_browsing_context) + m_current_top_level_browsing_context->page().set_window_rect_observer({}); + // 2. Set session's current top-level browsing context to context. m_current_top_level_browsing_context = browsing_context; + if (m_current_top_level_browsing_context) { + m_current_top_level_browsing_context->page().set_window_rect_observer(JS::create_heap_function(m_current_top_level_browsing_context->heap(), [this](Web::DevicePixelRect rect) { + if (m_pending_window_rect_requests > 0 && --m_pending_window_rect_requests == 0) + async_window_rect_updated(serialize_rect(rect.to_type())); + })); + } + // 3. Set the current browsing context with session and context. set_current_browsing_context(browsing_context); } diff --git a/Userland/Services/WebContent/WebDriverConnection.h b/Userland/Services/WebContent/WebDriverConnection.h index 20777b00d58..c2420550e84 100644 --- a/Userland/Services/WebContent/WebDriverConnection.h +++ b/Userland/Services/WebContent/WebDriverConnection.h @@ -161,6 +161,8 @@ private: // https://w3c.github.io/webdriver/#dfn-current-top-level-browsing-context JS::GCPtr m_current_top_level_browsing_context; + size_t m_pending_window_rect_requests { 0 }; + JS::GCPtr m_action_executor; JS::GCPtr m_document_observer; diff --git a/Userland/Services/WebContent/WebDriverServer.ipc b/Userland/Services/WebContent/WebDriverServer.ipc index d058d7c4d75..f376b375493 100644 --- a/Userland/Services/WebContent/WebDriverServer.ipc +++ b/Userland/Services/WebContent/WebDriverServer.ipc @@ -2,6 +2,7 @@ endpoint WebDriverServer { navigation_complete(Web::WebDriver::Response response) =| + window_rect_updated(Web::WebDriver::Response response) =| script_executed(Web::WebDriver::Response response) =| actions_performed(Web::WebDriver::Response response) =| dialog_closed(Web::WebDriver::Response response) =| diff --git a/Userland/Services/WebDriver/Client.cpp b/Userland/Services/WebDriver/Client.cpp index 8dca2449863..3447439073e 100644 --- a/Userland/Services/WebDriver/Client.cpp +++ b/Userland/Services/WebDriver/Client.cpp @@ -397,7 +397,7 @@ Web::WebDriver::Response Client::set_window_rect(Web::WebDriver::Parameters para { dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session//window/rect"); auto session = TRY(find_session_with_id(parameters[0])); - return session->web_content_connection().set_window_rect(payload); + return session->set_window_rect(payload); } // 11.8.3 Maximize Window, https://w3c.github.io/webdriver/#dfn-maximize-window diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index a3a2cdb90ec..f40915cac82 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -209,6 +209,13 @@ Web::WebDriver::Response Session::navigate_to(JsonValue payload) const }); } +Web::WebDriver::Response Session::set_window_rect(JsonValue payload) const +{ + return perform_async_action(web_content_connection().on_window_rect_updated, [&]() { + return web_content_connection().set_window_rect(move(payload)); + }); +} + Web::WebDriver::Response Session::execute_script(JsonValue payload, ScriptMode mode) const { return perform_async_action(web_content_connection().on_script_executed, [&]() { diff --git a/Userland/Services/WebDriver/Session.h b/Userland/Services/WebDriver/Session.h index 88c504aaf12..ee745dfe607 100644 --- a/Userland/Services/WebDriver/Session.h +++ b/Userland/Services/WebDriver/Session.h @@ -65,6 +65,8 @@ public: }; Web::WebDriver::Response execute_script(JsonValue, ScriptMode) const; + Web::WebDriver::Response set_window_rect(JsonValue) const; + Web::WebDriver::Response element_click(String) const; Web::WebDriver::Response element_send_keys(String, JsonValue) const; Web::WebDriver::Response perform_actions(JsonValue) const; diff --git a/Userland/Services/WebDriver/WebContentConnection.cpp b/Userland/Services/WebDriver/WebContentConnection.cpp index 71f0824e4b1..58819785130 100644 --- a/Userland/Services/WebDriver/WebContentConnection.cpp +++ b/Userland/Services/WebDriver/WebContentConnection.cpp @@ -26,6 +26,12 @@ void WebContentConnection::navigation_complete(Web::WebDriver::Response const& r on_navigation_complete(response); } +void WebContentConnection::window_rect_updated(Web::WebDriver::Response const& response) +{ + if (on_window_rect_updated) + on_window_rect_updated(response); +} + void WebContentConnection::script_executed(Web::WebDriver::Response const& response) { if (on_script_executed) diff --git a/Userland/Services/WebDriver/WebContentConnection.h b/Userland/Services/WebDriver/WebContentConnection.h index 04464d1a8d4..39a69478174 100644 --- a/Userland/Services/WebDriver/WebContentConnection.h +++ b/Userland/Services/WebDriver/WebContentConnection.h @@ -23,6 +23,7 @@ public: Function on_close; Function on_navigation_complete; + Function on_window_rect_updated; Function on_script_executed; Function on_actions_performed; Function on_dialog_closed; @@ -31,6 +32,7 @@ private: virtual void die() override; virtual void navigation_complete(Web::WebDriver::Response const&) override; + virtual void window_rect_updated(Web::WebDriver::Response const&) override; virtual void script_executed(Web::WebDriver::Response const&) override; virtual void actions_performed(Web::WebDriver::Response const&) override; virtual void dialog_closed(Web::WebDriver::Response const&) override;