diff options
author | Timothy Flynn <trflynn89@pm.me> | 2023-05-15 11:17:58 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-05-16 12:48:39 +0200 |
commit | c82f678fc615117caaf055219143960203ccd3e9 (patch) | |
tree | 5b9f1b63addc0fc85be8ff8fe195b7b48a019d70 | |
parent | d8f03dda08b26025469026e5498918e2fc352de5 (diff) | |
download | serenity-c82f678fc615117caaf055219143960203ccd3e9.zip |
LibWeb+WebContent: Add APIs to control video playback state
This allows for the browser process to control the play/pause state,
whether we paint user agent controls on the video, and whether the video
loops when it finishes playing.
-rw-r--r-- | Userland/Libraries/LibWeb/Page/Page.cpp | 80 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Page/Page.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibWebView/ViewImplementation.cpp | 15 | ||||
-rw-r--r-- | Userland/Libraries/LibWebView/ViewImplementation.h | 4 | ||||
-rw-r--r-- | Userland/Services/WebContent/ConnectionFromClient.cpp | 15 | ||||
-rw-r--r-- | Userland/Services/WebContent/ConnectionFromClient.h | 4 | ||||
-rw-r--r-- | Userland/Services/WebContent/PageHost.cpp | 15 | ||||
-rw-r--r-- | Userland/Services/WebContent/PageHost.h | 4 | ||||
-rw-r--r-- | Userland/Services/WebContent/WebContentServer.ipc | 4 |
9 files changed, 146 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index 7a6cd69240..e1e5f3e915 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -5,10 +5,12 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/ScopeGuard.h> #include <AK/SourceLocation.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/HTML/BrowsingContext.h> #include <LibWeb/HTML/EventLoop/EventLoop.h> +#include <LibWeb/HTML/HTMLVideoElement.h> #include <LibWeb/HTML/Scripting/Environments.h> #include <LibWeb/Page/Page.h> #include <LibWeb/Platform/EventLoopPlugin.h> @@ -281,4 +283,82 @@ void Page::did_request_video_context_menu(i32 video_id, CSSPixelPoint position, client().page_did_request_video_context_menu(position, url, target, modifiers, is_playing, has_user_agent_controls, is_looping); } +WebIDL::ExceptionOr<void> Page::toggle_video_play_state() +{ + auto video_element = video_context_menu_element(); + if (!video_element) + return {}; + + // FIXME: This runs from outside the context of any user script, so we do not have a running execution + // context. This pushes one to allow the promise creation hook to run. + auto& environment_settings = video_element->document().relevant_settings_object(); + environment_settings.prepare_to_run_script(); + + ScopeGuard guard { [&] { environment_settings.clean_up_after_running_script(); } }; + + if (video_element->potentially_playing()) + TRY(video_element->pause()); + else + TRY(video_element->play()); + + return {}; +} + +WebIDL::ExceptionOr<void> Page::toggle_video_loop_state() +{ + auto video_element = video_context_menu_element(); + if (!video_element) + return {}; + + // FIXME: This runs from outside the context of any user script, so we do not have a running execution + // context. This pushes one to allow the promise creation hook to run. + auto& environment_settings = video_element->document().relevant_settings_object(); + environment_settings.prepare_to_run_script(); + + ScopeGuard guard { [&] { environment_settings.clean_up_after_running_script(); } }; + + if (video_element->has_attribute(HTML::AttributeNames::loop)) + video_element->remove_attribute(HTML::AttributeNames::loop); + else + TRY(video_element->set_attribute(HTML::AttributeNames::loop, {})); + + return {}; +} + +WebIDL::ExceptionOr<void> Page::toggle_video_controls_state() +{ + auto video_element = video_context_menu_element(); + if (!video_element) + return {}; + + // FIXME: This runs from outside the context of any user script, so we do not have a running execution + // context. This pushes one to allow the promise creation hook to run. + auto& environment_settings = video_element->document().relevant_settings_object(); + environment_settings.prepare_to_run_script(); + + ScopeGuard guard { [&] { environment_settings.clean_up_after_running_script(); } }; + + if (video_element->has_attribute(HTML::AttributeNames::controls)) + video_element->remove_attribute(HTML::AttributeNames::controls); + else + TRY(video_element->set_attribute(HTML::AttributeNames::controls, {})); + + return {}; +} + +JS::GCPtr<HTML::HTMLVideoElement> Page::video_context_menu_element() +{ + if (!m_video_context_menu_element_id.has_value()) + return nullptr; + + auto* dom_node = DOM::Node::from_id(*m_video_context_menu_element_id); + if (dom_node == nullptr) + return nullptr; + + if (!is<HTML::HTMLVideoElement>(dom_node)) + return nullptr; + + return static_cast<HTML::HTMLVideoElement*>(dom_node); +} + } diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index ac0b9b073a..0b1ef936d9 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -116,10 +116,15 @@ public: void accept_dialog(); void did_request_video_context_menu(i32 video_id, CSSPixelPoint, AK::URL const&, DeprecatedString const& target, unsigned modifiers, bool is_playing, bool has_user_agent_controls, bool is_looping); + WebIDL::ExceptionOr<void> toggle_video_play_state(); + WebIDL::ExceptionOr<void> toggle_video_loop_state(); + WebIDL::ExceptionOr<void> toggle_video_controls_state(); bool pdf_viewer_supported() const { return m_pdf_viewer_supported; } private: + JS::GCPtr<HTML::HTMLVideoElement> video_context_menu_element(); + PageClient& m_client; JS::Handle<HTML::BrowsingContext> m_top_level_browsing_context; diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index 5d09a8ac68..85cd532f86 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -131,6 +131,21 @@ void ViewImplementation::run_javascript(StringView js_source) client().async_run_javascript(js_source); } +void ViewImplementation::toggle_video_play_state() +{ + client().async_toggle_video_play_state(); +} + +void ViewImplementation::toggle_video_loop_state() +{ + client().async_toggle_video_loop_state(); +} + +void ViewImplementation::toggle_video_controls_state() +{ + client().async_toggle_video_controls_state(); +} + void ViewImplementation::handle_resize() { resize_backing_stores_if_needed(WindowResizeInProgress::Yes); diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 21ec8de72a..23e8a5d2d4 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -70,6 +70,10 @@ public: void run_javascript(StringView); + void toggle_video_play_state(); + void toggle_video_loop_state(); + void toggle_video_controls_state(); + virtual void notify_server_did_layout(Badge<WebContentClient>, Gfx::IntSize content_size) = 0; virtual void notify_server_did_paint(Badge<WebContentClient>, i32 bitmap_id, Gfx::IntSize) = 0; virtual void notify_server_did_invalidate_content_rect(Badge<WebContentClient>, Gfx::IntRect const&) = 0; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 329d08953f..c248d6a0d0 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -756,6 +756,21 @@ void ConnectionFromClient::prompt_closed(Optional<String> const& response) m_page_host->prompt_closed(response); } +void ConnectionFromClient::toggle_video_play_state() +{ + m_page_host->toggle_video_play_state().release_value_but_fixme_should_propagate_errors(); +} + +void ConnectionFromClient::toggle_video_loop_state() +{ + m_page_host->toggle_video_loop_state().release_value_but_fixme_should_propagate_errors(); +} + +void ConnectionFromClient::toggle_video_controls_state() +{ + m_page_host->toggle_video_controls_state().release_value_but_fixme_should_propagate_errors(); +} + void ConnectionFromClient::inspect_accessibility_tree() { if (auto* doc = page().top_level_browsing_context().active_document()) { diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index 0cf634560a..d2ed7a58bc 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -95,6 +95,10 @@ private: virtual void confirm_closed(bool accepted) override; virtual void prompt_closed(Optional<String> const& response) override; + virtual void toggle_video_play_state() override; + virtual void toggle_video_loop_state() override; + virtual void toggle_video_controls_state() override; + virtual Messages::WebContentServer::TakeDocumentScreenshotResponse take_document_screenshot() override; virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override; diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index 0a505ee654..258a359e10 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -334,6 +334,21 @@ void PageHost::prompt_closed(Optional<String> response) page().prompt_closed(move(response)); } +Web::WebIDL::ExceptionOr<void> PageHost::toggle_video_play_state() +{ + return page().toggle_video_play_state(); +} + +Web::WebIDL::ExceptionOr<void> PageHost::toggle_video_loop_state() +{ + return page().toggle_video_loop_state(); +} + +Web::WebIDL::ExceptionOr<void> PageHost::toggle_video_controls_state() +{ + return page().toggle_video_controls_state(); +} + void PageHost::page_did_request_accept_dialog() { m_client.async_did_request_accept_dialog(); diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h index 08c259f217..9f8b068057 100644 --- a/Userland/Services/WebContent/PageHost.h +++ b/Userland/Services/WebContent/PageHost.h @@ -49,6 +49,10 @@ public: void confirm_closed(bool accepted); void prompt_closed(Optional<String> response); + Web::WebIDL::ExceptionOr<void> toggle_video_play_state(); + Web::WebIDL::ExceptionOr<void> toggle_video_loop_state(); + Web::WebIDL::ExceptionOr<void> toggle_video_controls_state(); + [[nodiscard]] Gfx::Color background_color() const; private: diff --git a/Userland/Services/WebContent/WebContentServer.ipc b/Userland/Services/WebContent/WebContentServer.ipc index 85331602d5..748b6deb87 100644 --- a/Userland/Services/WebContent/WebContentServer.ipc +++ b/Userland/Services/WebContent/WebContentServer.ipc @@ -76,4 +76,8 @@ endpoint WebContentServer alert_closed() =| confirm_closed(bool accepted) =| prompt_closed(Optional<String> response) =| + + toggle_video_play_state() =| + toggle_video_loop_state() =| + toggle_video_controls_state() =| } |