diff options
author | Martin Robinson <mrobinson@igalia.com> | 2025-04-09 21:41:53 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-09 19:41:53 +0000 |
commit | 2fe57cc2a2e5e7b982f7a32349117e2516724682 (patch) | |
tree | d8f75104771bcc8e83ae3adcc81f55f0e00ffc82 /components/servo | |
parent | 935db71183c9744455cf8e85262c3bed9b212984 (diff) | |
download | servo-2fe57cc2a2e5e7b982f7a32349117e2516724682.tar.gz servo-2fe57cc2a2e5e7b982f7a32349117e2516724682.zip |
libservo: Move animation tracking from `WindowMethods` to delegates (#36400)
This changes removes animation tracking from the `WindowMethods` trait
and moves it to `ServoDelegate` and `WebViewDelegate`.
- Animation changes per-`WebView` are now triggered in the compositor
only when the value is updated there, rather than right after ticking
animations.
- Both `WebView` and `Servo` now expose an `animation()` method, so
tracking animation state actually becomes unecessary in many cases,
such as that of desktop servoshell, which can just read the value
when the event loop spins.
Testing: No tests necessary as the API layer is still untested. Later,
tests will be added for the `WebView` API and this can be tested then.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Diffstat (limited to 'components/servo')
-rw-r--r-- | components/servo/examples/winit_minimal.rs | 14 | ||||
-rw-r--r-- | components/servo/lib.rs | 26 | ||||
-rw-r--r-- | components/servo/servo_delegate.rs | 5 | ||||
-rw-r--r-- | components/servo/webview.rs | 28 | ||||
-rw-r--r-- | components/servo/webview_delegate.rs | 5 |
5 files changed, 65 insertions, 13 deletions
diff --git a/components/servo/examples/winit_minimal.rs b/components/servo/examples/winit_minimal.rs index f19fd9763fe..1f6dbbe5c12 100644 --- a/components/servo/examples/winit_minimal.rs +++ b/components/servo/examples/winit_minimal.rs @@ -1,11 +1,11 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; use std::error::Error; use std::rc::Rc; -use compositing::windowing::{AnimationState, EmbedderMethods, WindowMethods}; +use compositing::windowing::{EmbedderMethods, WindowMethods}; use euclid::{Point2D, Scale, Size2D}; use servo::{RenderingContext, Servo, TouchEventType, WebView, WindowRenderingContext}; use servo_geometry::DeviceIndependentPixel; @@ -236,15 +236,11 @@ impl embedder_traits::EventLoopWaker for Waker { struct WindowDelegate { window: Window, - animation_state: Cell<AnimationState>, } impl WindowDelegate { fn new(window: Window) -> Self { - Self { - window, - animation_state: Cell::new(AnimationState::Idle), - } + Self { window } } } @@ -252,10 +248,6 @@ impl WindowMethods for WindowDelegate { fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> { Scale::new(self.window.scale_factor() as f32) } - - fn set_animation_state(&self, state: compositing::windowing::AnimationState) { - self.animation_state.set(state); - } } pub fn winit_size_to_euclid_size<T>(size: PhysicalSize<T>) -> Size2D<T, DevicePixel> { diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 3ef27875d3a..eea6ea01392 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -210,6 +210,8 @@ pub struct Servo { /// and deinitialization of the JS Engine. Multiprocess Servo instances have their /// own instance that exists in the content process instead. _js_engine_setup: Option<JSEngineSetup>, + /// Whether or not any WebView in this instance is animating or WebXR is enabled. + animating: Cell<bool>, } #[derive(Clone)] @@ -507,6 +509,7 @@ impl Servo { webviews: Default::default(), servo_errors: ServoErrorChannel::default(), _js_engine_setup: js_engine_setup, + animating: Cell::new(false), } } @@ -518,6 +521,15 @@ impl Servo { *self.delegate.borrow_mut() = delegate; } + /// Whether or not any [`WebView`] of this Servo instance has animating content, such as a CSS + /// animation or transition or is running `requestAnimationFrame` callbacks. In addition, this + /// returns true if WebXR content is running. This indicates that the embedding application + /// should be spinning the Servo event loop on regular intervals in order to trigger animation + /// updates. + pub fn animating(&self) -> bool { + self.animating.get() + } + /// **EXPERIMENTAL:** Intialize GL accelerated media playback. This currently only works on a limited number /// of platforms. This should be run *before* calling [`Servo::new`] and creating the first [`WebView`]. pub fn initialize_gl_accelerated_media(display: NativeDisplay, api: GlApi, context: GlContext) { @@ -555,6 +567,7 @@ impl Servo { self.compositor.borrow_mut().perform_updates(); self.send_new_frame_ready_messages(); + self.send_animating_changed_messages(); self.handle_delegate_errors(); self.clean_up_destroyed_webview_handles(); @@ -580,6 +593,19 @@ impl Servo { } } + fn send_animating_changed_messages(&self) { + let animating = self.compositor.borrow().webxr_running() || + self.webviews + .borrow() + .values() + .filter_map(WebView::from_weak_handle) + .any(|webview| webview.animating()); + if animating != self.animating.get() { + self.animating.set(animating); + self.delegate().notify_animating_changed(animating); + } + } + fn handle_delegate_errors(&self) { while let Some(error) = self.servo_errors.try_recv() { self.delegate().notify_error(self, error); diff --git a/components/servo/servo_delegate.rs b/components/servo/servo_delegate.rs index 8ec53a4790b..b119a962029 100644 --- a/components/servo/servo_delegate.rs +++ b/components/servo/servo_delegate.rs @@ -28,6 +28,11 @@ pub trait ServoDelegate { /// Request a DevTools connection from a DevTools client. Typically an embedder application /// will show a permissions prompt when this happens to confirm a connection is allowed. fn request_devtools_connection(&self, _servo: &Servo, _request: AllowOrDenyRequest) {} + /// Any [`WebView`] in this Servo instance has either started to animate or WebXR is + /// running. When a [`WebView`] is animating, it is up to the embedding application + /// ensure that `Servo::spin_event_loop` is called at regular intervals in order to + /// update the painted contents of the [`WebView`]. + fn notify_animating_changed(&self, _animating: bool) {} /// Triggered when Servo will load a web (HTTP/HTTPS) resource. The load may be /// intercepted and alternate contents can be loaded by the client by calling /// [`WebResourceLoad::intercept`]. If not handled, the load will continue as normal. diff --git a/components/servo/webview.rs b/components/servo/webview.rs index ed243d56421..92564753168 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -81,6 +81,7 @@ pub(crate) struct WebViewInner { page_title: Option<String>, favicon_url: Option<Url>, focused: bool, + animating: bool, cursor: Cursor, } @@ -110,6 +111,7 @@ impl WebView { page_title: None, favicon_url: None, focused: false, + animating: false, cursor: Cursor::Pointer, }))); @@ -265,6 +267,22 @@ impl WebView { .send(EmbedderToConstellationMessage::BlurWebView); } + /// Whether or not this [`WebView`] has animating content, such as a CSS animation or + /// transition or is running `requestAnimationFrame` callbacks. This indicates that the + /// embedding application should be spinning the Servo event loop on regular intervals + /// in order to trigger animation updates. + pub fn animating(self) -> bool { + self.inner().animating + } + + pub(crate) fn set_animating(self, new_value: bool) { + if self.inner().animating == new_value { + return; + } + self.inner_mut().animating = new_value; + self.delegate().notify_animating_changed(self, new_value); + } + pub fn rect(&self) -> DeviceRect { self.inner().rect } @@ -475,12 +493,18 @@ struct ServoRendererWebView { } impl RendererWebView for ServoRendererWebView { + fn id(&self) -> WebViewId { + self.id + } + fn screen_geometry(&self) -> Option<ScreenGeometry> { let webview = WebView::from_weak_handle(&self.weak_handle)?; webview.delegate().screen_geometry(webview) } - fn id(&self) -> WebViewId { - self.id + fn set_animating(&self, new_value: bool) { + if let Some(webview) = WebView::from_weak_handle(&self.weak_handle) { + webview.set_animating(new_value); + } } } diff --git a/components/servo/webview_delegate.rs b/components/servo/webview_delegate.rs index b631eae7404..ac3dc7a5152 100644 --- a/components/servo/webview_delegate.rs +++ b/components/servo/webview_delegate.rs @@ -375,6 +375,11 @@ pub trait WebViewDelegate { /// This [`WebView`] has either become focused or lost focus. Whether or not the /// [`WebView`] is focused can be accessed via [`WebView::focused`]. fn notify_focus_changed(&self, _webview: WebView, _focused: bool) {} + /// This [`WebView`] has either started to animate or stopped animating. When a + /// [`WebView`] is animating, it is up to the embedding application ensure that + /// `Servo::spin_event_loop` is called at regular intervals in order to update the + /// painted contents of the [`WebView`]. + fn notify_animating_changed(&self, _webview: WebView, _animating: bool) {} /// The `LoadStatus` of the currently loading or loaded page in this [`WebView`] has changed. The new /// status can accessed via [`WebView::load_status`]. fn notify_load_status_changed(&self, _webview: WebView, _status: LoadStatus) {} |