aboutsummaryrefslogtreecommitdiffstats
path: root/components/servo
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2025-04-09 21:41:53 +0200
committerGitHub <noreply@github.com>2025-04-09 19:41:53 +0000
commit2fe57cc2a2e5e7b982f7a32349117e2516724682 (patch)
treed8f75104771bcc8e83ae3adcc81f55f0e00ffc82 /components/servo
parent935db71183c9744455cf8e85262c3bed9b212984 (diff)
downloadservo-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.rs14
-rw-r--r--components/servo/lib.rs26
-rw-r--r--components/servo/servo_delegate.rs5
-rw-r--r--components/servo/webview.rs28
-rw-r--r--components/servo/webview_delegate.rs5
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) {}