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>
This commit is contained in:
Martin Robinson 2025-04-09 21:41:53 +02:00 committed by GitHub
parent 935db71183
commit 2fe57cc2a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 153 additions and 125 deletions

View file

@ -13,7 +13,7 @@ use std::{env, fs};
use euclid::Scale;
use log::{info, trace, warn};
use servo::compositing::windowing::{AnimationState, WindowMethods};
use servo::compositing::windowing::WindowMethods;
use servo::config::opts::Opts;
use servo::config::prefs::Preferences;
use servo::servo_config::pref;
@ -146,9 +146,6 @@ impl App {
fn hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
self.0.hidpi_factor()
}
fn set_animation_state(&self, state: AnimationState) {
self.0.set_animation_state(state);
}
}
let mut user_content_manager = UserContentManager::new();
@ -183,8 +180,12 @@ impl App {
self.state = AppState::Running(running_state);
}
pub fn is_animating(&self) -> bool {
self.windows.iter().any(|(_, window)| window.is_animating())
pub(crate) fn animating(&self) -> bool {
match self.state {
AppState::Initializing => false,
AppState::Running(ref running_app_state) => running_app_state.servo().animating(),
AppState::ShuttingDown => false,
}
}
/// Handle events with winit contexts
@ -401,10 +402,8 @@ impl ApplicationHandler<WakerEvent> for App {
window.handle_winit_event(state.clone(), event);
}
let animating = self.is_animating();
// Block until the window gets an event
if !animating || self.suspended.get() {
if !self.animating() || self.suspended.get() {
event_loop.set_control_flow(ControlFlow::Wait);
} else {
event_loop.set_control_flow(ControlFlow::Poll);
@ -427,7 +426,7 @@ impl ApplicationHandler<WakerEvent> for App {
);
self.t = now;
if !matches!(self.state, AppState::Running(_)) {
if !matches!(self.state, AppState::Running(..)) {
return;
};
let Some(window) = self.windows.values().next() else {
@ -435,10 +434,8 @@ impl ApplicationHandler<WakerEvent> for App {
};
let window = window.clone();
let animating = self.is_animating();
// Block until the window gets an event
if !animating || self.suspended.get() {
if !self.animating() || self.suspended.get() {
event_loop.set_control_flow(ControlFlow::Wait);
} else {
event_loop.set_control_flow(ControlFlow::Poll);

View file

@ -96,7 +96,7 @@ impl EventsLoop {
if !app.handle_events_with_headless() {
break;
}
if !app.is_animating() {
if !app.animating() {
*flag.lock().unwrap() = false;
}
}

View file

@ -14,7 +14,7 @@ use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vec
use keyboard_types::{Modifiers, ShortcutMatcher};
use log::{debug, info};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
use servo::compositing::windowing::{AnimationState, WebRenderDebugOption, WindowMethods};
use servo::compositing::windowing::{WebRenderDebugOption, WindowMethods};
use servo::servo_config::pref;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::ScrollLocation;
@ -62,7 +62,6 @@ pub struct Window {
/// A map of winit's key codes to key values that are interpreted from
/// winit's ReceivedChar events.
keys_down: RefCell<HashMap<LogicalKey, Key>>,
animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>,
device_pixel_ratio_override: Option<f32>,
xr_window_poses: RefCell<Vec<Rc<XRWindowPose>>>,
@ -151,7 +150,6 @@ impl Window {
webview_relative_mouse_point: Cell::new(Point2D::zero()),
last_pressed: Cell::new(None),
keys_down: RefCell::new(HashMap::new()),
animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false),
inner_size: Cell::new(inner_size),
monitor,
@ -570,10 +568,6 @@ impl WindowPortsMethods for Window {
self.winit_window.set_cursor_visible(true);
}
fn is_animating(&self) -> bool {
self.animation_state.get() == AnimationState::Animating
}
fn id(&self) -> winit::window::WindowId {
self.winit_window.id()
}
@ -772,10 +766,6 @@ impl WindowMethods for Window {
self.device_pixel_ratio_override()
.unwrap_or_else(|| self.device_hidpi_factor())
}
fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state);
}
}
fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType {

View file

@ -9,7 +9,7 @@ use std::rc::Rc;
use euclid::num::Zero;
use euclid::{Length, Scale, Size2D};
use servo::compositing::windowing::{AnimationState, WindowMethods};
use servo::compositing::windowing::WindowMethods;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntSize, DevicePixel};
use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext};
@ -20,7 +20,6 @@ use crate::desktop::window_trait::WindowPortsMethods;
use crate::prefs::ServoShellPreferences;
pub struct Window {
animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>,
device_pixel_ratio_override: Option<Scale<f32, DeviceIndependentPixel, DevicePixel>>,
inner_size: Cell<DeviceIntSize>,
@ -50,7 +49,6 @@ impl Window {
});
let window = Window {
animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false),
device_pixel_ratio_override,
inner_size: Cell::new(inner_size),
@ -120,10 +118,6 @@ impl WindowPortsMethods for Window {
self.fullscreen.get()
}
fn is_animating(&self) -> bool {
self.animation_state.get() == AnimationState::Animating
}
fn handle_winit_event(&self, _: Rc<RunningAppState>, _: winit::event::WindowEvent) {
// Not expecting any winit events.
}
@ -157,8 +151,4 @@ impl WindowMethods for Window {
self.device_pixel_ratio_override()
.unwrap_or_else(|| self.device_hidpi_factor())
}
fn set_animation_state(&self, state: AnimationState) {
self.animation_state.set(state);
}
}

View file

@ -28,7 +28,6 @@ pub trait WindowPortsMethods: WindowMethods {
fn page_height(&self) -> f32;
fn get_fullscreen(&self) -> bool;
fn handle_winit_event(&self, state: Rc<RunningAppState>, event: winit::event::WindowEvent);
fn is_animating(&self) -> bool;
fn set_title(&self, _title: &str) {}
/// Request a new inner size for the window, not including external decorations.
fn request_resize(&self, webview: &WebView, inner_size: DeviceIntSize)