servoshell: Remove HeadedWindow-specific methods from PlatformWindow (#41773)

Instead of having `HeadedWindow`-specific methods here, just expose a
way to access the concrete type of a window. This is also exposed for
embedded ports and unused. They will use it in an upcoming change.

Testing: This shouldn't change behavior and is thus covered by existing
tests.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson
2026-01-08 16:36:43 +01:00
committed by GitHub
parent 56bc26a7cc
commit b89f47913c
7 changed files with 112 additions and 115 deletions

View File

@@ -28,7 +28,7 @@ use crate::desktop::tracing::trace_winit_event;
use crate::parser::get_default_url;
use crate::prefs::ServoShellPreferences;
use crate::running_app_state::RunningAppState;
use crate::window::PlatformWindow;
use crate::window::{PlatformWindow, ServoShellWindowId};
pub(crate) enum AppState {
Initializing,
@@ -186,17 +186,13 @@ impl ApplicationHandler<AppEvent> for App {
);
self.t = now;
{
let AppState::Running(state) = &self.state else {
return;
};
let window_id: u64 = window_id.into();
if let Some(window) = state.window(window_id.into()) {
window.platform_window().handle_winit_window_event(
state.clone(),
window,
window_event,
);
let AppState::Running(state) = &self.state else {
return;
};
if let Some(window) = state.window(ServoShellWindowId::from(u64::from(window_id))) {
if let Some(headed_window) = window.platform_window().as_headed_window() {
headed_window.handle_winit_window_event(state.clone(), window, window_event);
}
}
@@ -208,15 +204,16 @@ impl ApplicationHandler<AppEvent> for App {
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, app_event: AppEvent) {
let AppState::Running(state) = &self.state else {
return;
};
if let Some(window) = app_event
.window_id()
.and_then(|window_id| state.window(ServoShellWindowId::from(u64::from(window_id))))
{
let AppState::Running(state) = &self.state else {
return;
};
if let Some(window_id) = app_event.window_id() {
let window_id: u64 = window_id.into();
if let Some(window) = state.window(window_id.into()) {
window.platform_window().handle_winit_app_event(app_event);
}
if let Some(headed_window) = window.platform_window().as_headed_window() {
headed_window.handle_winit_app_event(app_event);
}
}

View File

@@ -533,68 +533,8 @@ impl HeadedWindow {
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel> {
self.gui.borrow().toolbar_height()
}
}
impl PlatformWindow for HeadedWindow {
fn has_winit_window(&self) -> bool {
true
}
fn screen_geometry(&self) -> ScreenGeometry {
let hidpi_factor = self.hidpi_scale_factor();
let toolbar_size = Size2D::new(0.0, (self.toolbar_height() * self.hidpi_scale_factor()).0);
let screen_size = self.screen_size.to_f32() * hidpi_factor;
// FIXME: In reality, this should subtract screen space used by the system interface
// elements, but it is difficult to get this value with `winit` currently. See:
// See https://github.com/rust-windowing/winit/issues/2494
let available_screen_size = screen_size - toolbar_size;
let window_rect = DeviceIntRect::from_origin_and_size(
winit_position_to_euclid_point(self.winit_window.outer_position().unwrap_or_default()),
winit_size_to_euclid_size(self.winit_window.outer_size()).to_i32(),
);
ScreenGeometry {
size: screen_size.to_i32(),
available_size: available_screen_size.to_i32(),
window_rect,
}
}
fn device_hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
Scale::new(self.winit_window.scale_factor() as f32)
}
fn hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
self.device_pixel_ratio_override
.map(Scale::new)
.unwrap_or_else(|| self.device_hidpi_scale_factor())
}
fn rebuild_user_interface(&self, state: &RunningAppState, window: &ServoShellWindow) {
self.gui.borrow_mut().update(state, window, self);
}
fn update_user_interface_state(&self, _: &RunningAppState, window: &ServoShellWindow) -> bool {
let title = window
.active_webview()
.and_then(|webview| {
webview
.page_title()
.filter(|title| !title.is_empty())
.map(|title| title.to_string())
.or_else(|| webview.url().map(|url| url.to_string()))
})
.unwrap_or_else(|| INITIAL_WINDOW_TITLE.to_string());
if title != *self.last_title.borrow() {
self.winit_window.set_title(&title);
*self.last_title.borrow_mut() = title;
}
self.gui.borrow_mut().update_webview_data(window)
}
fn handle_winit_window_event(
pub(crate) fn handle_winit_window_event(
&self,
state: Rc<RunningAppState>,
window: Rc<ServoShellWindow>,
@@ -816,7 +756,7 @@ impl PlatformWindow for HeadedWindow {
}
}
fn handle_winit_app_event(&self, app_event: AppEvent) {
pub(crate) fn handle_winit_app_event(&self, app_event: AppEvent) {
if let AppEvent::Accessibility(ref event) = app_event {
if self
.gui
@@ -827,6 +767,67 @@ impl PlatformWindow for HeadedWindow {
}
}
}
}
impl PlatformWindow for HeadedWindow {
fn as_headed_window(&self) -> Option<&Self> {
Some(self)
}
fn screen_geometry(&self) -> ScreenGeometry {
let hidpi_factor = self.hidpi_scale_factor();
let toolbar_size = Size2D::new(0.0, (self.toolbar_height() * self.hidpi_scale_factor()).0);
let screen_size = self.screen_size.to_f32() * hidpi_factor;
// FIXME: In reality, this should subtract screen space used by the system interface
// elements, but it is difficult to get this value with `winit` currently. See:
// See https://github.com/rust-windowing/winit/issues/2494
let available_screen_size = screen_size - toolbar_size;
let window_rect = DeviceIntRect::from_origin_and_size(
winit_position_to_euclid_point(self.winit_window.outer_position().unwrap_or_default()),
winit_size_to_euclid_size(self.winit_window.outer_size()).to_i32(),
);
ScreenGeometry {
size: screen_size.to_i32(),
available_size: available_screen_size.to_i32(),
window_rect,
}
}
fn device_hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
Scale::new(self.winit_window.scale_factor() as f32)
}
fn hidpi_scale_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
self.device_pixel_ratio_override
.map(Scale::new)
.unwrap_or_else(|| self.device_hidpi_scale_factor())
}
fn rebuild_user_interface(&self, state: &RunningAppState, window: &ServoShellWindow) {
self.gui.borrow_mut().update(state, window, self);
}
fn update_user_interface_state(&self, _: &RunningAppState, window: &ServoShellWindow) -> bool {
let title = window
.active_webview()
.and_then(|webview| {
webview
.page_title()
.filter(|title| !title.is_empty())
.map(|title| title.to_string())
.or_else(|| webview.url().map(|url| url.to_string()))
})
.unwrap_or_else(|| INITIAL_WINDOW_TITLE.to_string());
if title != *self.last_title.borrow() {
self.winit_window.set_title(&title);
*self.last_title.borrow_mut() = title;
}
self.gui.borrow_mut().update_webview_data(window)
}
fn request_repaint(&self, window: &ServoShellWindow) {
self.winit_window.request_redraw();
@@ -1036,6 +1037,10 @@ impl PlatformWindow for HeadedWindow {
self.winit_window.focus_window();
}
fn has_platform_focus(&self) -> bool {
self.winit_window.has_focus()
}
fn show_embedder_control(&self, webview_id: WebViewId, embedder_control: EmbedderControl) {
let control_id = embedder_control.id();
match embedder_control {

View File

@@ -13,7 +13,7 @@ pub(crate) mod event_loop;
pub(crate) mod gamepad;
pub mod geometry;
mod gui;
mod headed_window;
pub(crate) mod headed_window;
mod headless_window;
mod keyutils;
mod protocols;

View File

@@ -25,7 +25,7 @@ use crate::prefs::ServoShellPreferences;
use crate::running_app_state::{RunningAppState, UserInterfaceCommand};
use crate::window::{PlatformWindow, ServoShellWindow, ServoShellWindowId};
pub(super) struct EmbeddedPlatformWindow {
pub(crate) struct EmbeddedPlatformWindow {
host: Box<dyn HostTrait>,
rendering_context: Rc<WindowRenderingContext>,
refresh_driver: Rc<VsyncRefreshDriver>,
@@ -47,6 +47,10 @@ pub(super) struct EmbeddedPlatformWindow {
}
impl PlatformWindow for EmbeddedPlatformWindow {
fn as_headed_window(&self) -> Option<&Self> {
Some(self)
}
fn id(&self) -> ServoShellWindowId {
0.into()
}

View File

@@ -4,7 +4,7 @@
#[cfg(target_os = "android")]
mod android;
mod app;
pub(crate) mod app;
#[cfg(feature = "gamepad")]
pub(crate) mod gamepad;
mod host_trait;

View File

@@ -247,18 +247,17 @@ impl RunningAppState {
platform_window: Rc<dyn PlatformWindow>,
initial_url: Url,
) -> Rc<ServoShellWindow> {
let has_winit_window = platform_window.has_winit_window();
let window = Rc::new(ServoShellWindow::new(platform_window));
// For [`HeadedWindow`], it is up to the `winit::event::WindowEvent::Focused`.
// Otherwise, newly created windows are automatically focused.
if !has_winit_window {
self.focus_window(window.clone());
}
let window = Rc::new(ServoShellWindow::new(platform_window.clone()));
window.create_and_activate_toplevel_webview(self.clone(), initial_url);
self.windows
.borrow_mut()
.insert(window.id(), window.clone());
// If the window already has platform focus, mark it as focused in our application state.
if platform_window.has_platform_focus() {
self.focus_window(window.clone());
}
window
}

View File

@@ -366,26 +366,6 @@ pub(crate) trait PlatformWindow {
fn update_user_interface_state(&self, _: &RunningAppState, _: &ServoShellWindow) -> bool {
false
}
/// Handle a winit [`WindowEvent`]. Returns `true` if the event loop should continue
/// and `false` otherwise.
///
/// TODO: This should be handled internally in the winit window if possible so that it
/// makes more sense when we are mixing headed and headless windows.
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
fn handle_winit_window_event(
&self,
_: Rc<RunningAppState>,
_: Rc<ServoShellWindow>,
_: winit::event::WindowEvent,
) {
}
/// Handle a winit [`AppEvent`]. Returns `true` if the event loop should continue and
/// `false` otherwise.
///
/// TODO: This should be handled internally in the winit window if possible so that it
/// makes more sense when we are mixing headed and headless windows.
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
fn handle_winit_app_event(&self, _: crate::desktop::event_loop::AppEvent) {}
/// Request that the window redraw itself. It is up to the window to do this
/// once the windowing system is ready. If this is a headless window, the redraw
/// will happen immediately.
@@ -413,6 +393,9 @@ pub(crate) trait PlatformWindow {
fn window_rect(&self) -> DeviceIndependentIntRect;
fn maximize(&self, _: &WebView) {}
fn focus(&self) {}
fn has_platform_focus(&self) -> bool {
true
}
fn show_embedder_control(&self, _: WebViewId, _: EmbedderControl) {}
fn hide_embedder_control(&self, _: WebViewId, _: EmbedderControlId) {}
@@ -438,7 +421,16 @@ pub(crate) trait PlatformWindow {
fn notify_media_session_event(&self, _: MediaSessionEvent) {}
fn notify_crashed(&self, _: WebView, _reason: String, _backtrace: Option<String>) {}
fn show_console_message(&self, _level: ConsoleLogLevel, _message: &str) {}
fn has_winit_window(&self) -> bool {
false
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
/// If this window is a headed window, access the concrete type.
fn as_headed_window(&self) -> Option<&crate::desktop::headed_window::HeadedWindow> {
None
}
#[cfg(any(target_os = "android", target_env = "ohos"))]
/// If this window is a headed window, access the concrete type.
fn as_headed_window(&self) -> Option<&crate::egl::app::EmbeddedPlatformWindow> {
None
}
}