From fa83cc722c7b78fbe266efc7831822d670523ced Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 28 Oct 2024 23:37:11 -0400 Subject: [PATCH] LibWeb+WebContent+WebDriver+UI: Make window rect updates asynchronous It's currently possible for window size/position updates to hang, as the underlying IPCs are synchronous. This updates the WebDriver endpoint to be async, to unblock the WebContent process while the update is ongoing. The UI process is now responsible for informing WebContent when the update is complete. --- Ladybird/AppKit/UI/LadybirdWebView.mm | 10 +++--- Ladybird/Qt/Tab.cpp | 4 +-- Userland/Libraries/LibWeb/Page/Page.cpp | 7 ++++ Userland/Libraries/LibWeb/Page/Page.h | 8 +++-- .../LibWebView/ViewImplementation.cpp | 5 +++ .../Libraries/LibWebView/ViewImplementation.h | 5 +-- .../Libraries/LibWebView/WebContentClient.cpp | 12 +++---- .../Libraries/LibWebView/WebContentClient.h | 4 +-- .../WebContent/ConnectionFromClient.cpp | 6 ++++ .../WebContent/ConnectionFromClient.h | 1 + Userland/Services/WebContent/PageClient.cpp | 8 ++--- Userland/Services/WebContent/PageClient.h | 4 +-- .../Services/WebContent/WebContentClient.ipc | 4 +-- .../Services/WebContent/WebContentServer.ipc | 1 + .../WebContent/WebDriverConnection.cpp | 36 ++++++++++++------- .../Services/WebContent/WebDriverConnection.h | 2 ++ .../Services/WebContent/WebDriverServer.ipc | 1 + Userland/Services/WebDriver/Client.cpp | 2 +- Userland/Services/WebDriver/Session.cpp | 7 ++++ Userland/Services/WebDriver/Session.h | 2 ++ .../WebDriver/WebContentConnection.cpp | 6 ++++ .../Services/WebDriver/WebContentConnection.h | 2 ++ 22 files changed, 94 insertions(+), 43 deletions(-) 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;