diff options
author | Martin Robinson <mrobinson@igalia.com> | 2025-04-16 18:58:52 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-16 16:58:52 +0000 |
commit | d8a7abda69dc2e03a845cb053c28764babd5b9de (patch) | |
tree | bb15a30aa8729eda1feaeec4ea9a9d7294020be7 | |
parent | 7a8e75266ff2c138f212a301de9774eafb2b3143 (diff) | |
download | servo-d8a7abda69dc2e03a845cb053c28764babd5b9de.tar.gz servo-d8a7abda69dc2e03a845cb053c28764babd5b9de.zip |
libservo: Expose a `ServoBuilder` (#36549)
Expose a `ServoBuilder` for easily creating Servo instances using
default values. This change enables removing `EmbedderTraits`.
Testing: This is covered by `Servo` unit tests.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | components/compositing/windowing.rs | 25 | ||||
-rw-r--r-- | components/servo/examples/winit_minimal.rs | 29 | ||||
-rw-r--r-- | components/servo/lib.rs | 104 | ||||
-rw-r--r-- | components/servo/tests/common/mod.rs | 21 | ||||
-rw-r--r-- | components/shared/embedder/lib.rs | 2 | ||||
-rw-r--r-- | components/webxr/Cargo.toml | 1 | ||||
-rw-r--r-- | components/webxr/lib.rs | 5 | ||||
-rw-r--r-- | ports/servoshell/desktop/app.rs | 62 | ||||
-rw-r--r-- | ports/servoshell/desktop/embedder.rs | 71 | ||||
-rw-r--r-- | ports/servoshell/desktop/mod.rs | 2 | ||||
-rw-r--r-- | ports/servoshell/desktop/webxr.rs | 78 | ||||
-rw-r--r-- | ports/servoshell/egl/android.rs | 7 | ||||
-rw-r--r-- | ports/servoshell/egl/android/simpleservo.rs | 34 | ||||
-rw-r--r-- | ports/servoshell/egl/app_state.rs | 48 | ||||
-rw-r--r-- | ports/servoshell/egl/ohos.rs | 5 | ||||
-rw-r--r-- | ports/servoshell/egl/ohos/simpleservo.rs | 28 |
17 files changed, 252 insertions, 271 deletions
diff --git a/Cargo.lock b/Cargo.lock index 29a9c388625..7a563a0bf14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8595,6 +8595,7 @@ name = "webxr" version = "0.0.1" dependencies = [ "crossbeam-channel", + "embedder_traits", "euclid", "glow", "log", diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index b35fed5288a..e047e54b276 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -2,11 +2,6 @@ * 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/. */ -//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. - -use embedder_traits::EventLoopWaker; -use net::protocols::ProtocolRegistry; - /// Various debug and profiling flags that WebRender supports. #[derive(Clone)] pub enum WebRenderDebugOption { @@ -14,23 +9,3 @@ pub enum WebRenderDebugOption { TextureCacheDebug, RenderTargetDebug, } - -pub trait EmbedderMethods { - /// Returns a thread-safe object to wake up the window's event loop. - fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker>; - - #[cfg(feature = "webxr")] - /// Register services with a WebXR Registry. - fn register_webxr( - &mut self, - _: &mut webxr::MainThreadRegistry, - _: embedder_traits::EmbedderProxy, - ) { - } - - /// Returns the protocol handlers implemented by that embedder. - /// They will be merged with the default internal ones. - fn get_protocol_handlers(&self) -> ProtocolRegistry { - ProtocolRegistry::default() - } -} diff --git a/components/servo/examples/winit_minimal.rs b/components/servo/examples/winit_minimal.rs index edfd532654f..91d3190e732 100644 --- a/components/servo/examples/winit_minimal.rs +++ b/components/servo/examples/winit_minimal.rs @@ -5,10 +5,10 @@ use std::cell::RefCell; use std::error::Error; use std::rc::Rc; -use compositing::windowing::EmbedderMethods; use euclid::{Scale, Size2D}; use servo::{ - RenderingContext, Servo, TouchEventType, WebView, WebViewBuilder, WindowRenderingContext, + RenderingContext, Servo, ServoBuilder, TouchEventType, WebView, WebViewBuilder, + WindowRenderingContext, }; use tracing::warn; use url::Url; @@ -95,15 +95,9 @@ impl ApplicationHandler<WakerEvent> for App { let _ = rendering_context.make_current(); - let servo = Servo::new( - Default::default(), - Default::default(), - rendering_context.clone(), - Box::new(EmbedderDelegate { - waker: waker.clone(), - }), - Default::default(), - ); + let servo = ServoBuilder::new(rendering_context.clone()) + .event_loop_waker(Box::new(waker.clone())) + .build(); servo.setup_logging(); let app_state = Rc::new(AppState { @@ -204,19 +198,6 @@ impl ApplicationHandler<WakerEvent> for App { } } -struct EmbedderDelegate { - waker: Waker, -} - -impl EmbedderMethods for EmbedderDelegate { - // FIXME: rust-analyzer “Implement missing members” autocompletes this as - // webxr_api::MainThreadWaker, which is not available when building without - // libservo/webxr, and even if it was, it would fail to compile with E0053. - fn create_event_loop_waker(&mut self) -> Box<dyn embedder_traits::EventLoopWaker> { - Box::new(self.waker.clone()) - } -} - #[derive(Clone)] struct Waker(winit::event_loop::EventLoopProxy<WakerEvent>); #[derive(Debug)] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 62ef9e85dde..b8f72554ba5 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -42,7 +42,6 @@ use canvas::WebGLComm; use canvas::canvas_paint_thread::CanvasPaintThread; use canvas_traits::webgl::{GlType, WebGLThreads}; use clipboard_delegate::StringRequest; -use compositing::windowing::EmbedderMethods; use compositing::{IOCompositor, InitialCompositorState}; pub use compositing_traits::rendering_context::{ OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext, @@ -247,26 +246,18 @@ impl webrender_api::RenderNotifier for RenderNotifier { impl Servo { #[cfg_attr( feature = "tracing", - tracing::instrument( - skip(preferences, rendering_context, embedder), - fields(servo_profiling = true), - level = "trace", - ) + tracing::instrument(skip(builder), fields(servo_profiling = true), level = "trace",) )] - pub fn new( - opts: Opts, - preferences: Preferences, - rendering_context: Rc<dyn RenderingContext>, - mut embedder: Box<dyn EmbedderMethods>, - user_content_manager: UserContentManager, - ) -> Self { + fn new(builder: ServoBuilder) -> Self { // Global configuration options, parsed from the command line. - opts::set_options(opts); + let opts = builder.opts.map(|opts| *opts); + opts::set_options(opts.unwrap_or_default()); let opts = opts::get(); // Set the preferences globally. // TODO: It would be better to make these private to a particular Servo instance. - servo_config::prefs::set(preferences); + let preferences = builder.preferences.map(|opts| *opts); + servo_config::prefs::set(preferences.unwrap_or_default()); use std::sync::atomic::Ordering; @@ -282,6 +273,7 @@ impl Servo { } // Get GL bindings + let rendering_context = builder.rendering_context; let webrender_gl = rendering_context.gleam_gl_api(); // Make sure the gl context is made current. @@ -297,7 +289,7 @@ impl Servo { // the client window and the compositor. This channel is unique because // messages to client may need to pump a platform-specific event loop // to deliver the message. - let event_loop_waker = embedder.create_event_loop_waker(); + let event_loop_waker = builder.event_loop_waker; let (compositor_proxy, compositor_receiver) = create_compositor_channel(event_loop_waker.clone()); let (embedder_proxy, embedder_receiver) = create_embedder_channel(event_loop_waker.clone()); @@ -424,7 +416,7 @@ impl Servo { .expect("Failed to create WebXR device registry"); #[cfg(feature = "webxr")] if pref!(dom_webxr_enabled) { - embedder.register_webxr(&mut webxr_main_thread, embedder_proxy.clone()); + builder.webxr_registry.register(&mut webxr_main_thread); } #[cfg(feature = "webgpu")] @@ -447,7 +439,7 @@ impl Servo { // Create the constellation, which maintains the engine pipelines, including script and // layout, as well as the navigation context. let mut protocols = ProtocolRegistry::with_internal_protocols(); - protocols.merge(embedder.get_protocol_handlers()); + protocols.merge(builder.protocol_registry); let constellation_chan = create_constellation( opts.config_dir.clone(), @@ -465,7 +457,7 @@ impl Servo { #[cfg(feature = "webgpu")] wgpu_image_map, protocols, - user_content_manager, + builder.user_content_manager, ); if cfg!(feature = "webdriver") { @@ -1204,3 +1196,77 @@ fn create_sandbox() { fn create_sandbox() { panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android."); } + +struct DefaultEventLoopWaker; + +impl EventLoopWaker for DefaultEventLoopWaker { + fn clone_box(&self) -> Box<dyn EventLoopWaker> { + Box::new(DefaultEventLoopWaker) + } +} + +#[cfg(feature = "webxr")] +struct DefaultWebXrRegistry; +#[cfg(feature = "webxr")] +impl webxr::WebXrRegistry for DefaultWebXrRegistry {} + +pub struct ServoBuilder { + rendering_context: Rc<dyn RenderingContext>, + opts: Option<Box<Opts>>, + preferences: Option<Box<Preferences>>, + event_loop_waker: Box<dyn EventLoopWaker>, + user_content_manager: UserContentManager, + protocol_registry: ProtocolRegistry, + #[cfg(feature = "webxr")] + webxr_registry: Box<dyn webxr::WebXrRegistry>, +} + +impl ServoBuilder { + pub fn new(rendering_context: Rc<dyn RenderingContext>) -> Self { + Self { + rendering_context, + opts: None, + preferences: None, + event_loop_waker: Box::new(DefaultEventLoopWaker), + user_content_manager: UserContentManager::default(), + protocol_registry: ProtocolRegistry::default(), + #[cfg(feature = "webxr")] + webxr_registry: Box::new(DefaultWebXrRegistry), + } + } + + pub fn build(self) -> Servo { + Servo::new(self) + } + + pub fn opts(mut self, opts: Opts) -> Self { + self.opts = Some(Box::new(opts)); + self + } + + pub fn preferences(mut self, preferences: Preferences) -> Self { + self.preferences = Some(Box::new(preferences)); + self + } + + pub fn event_loop_waker(mut self, event_loop_waker: Box<dyn EventLoopWaker>) -> Self { + self.event_loop_waker = event_loop_waker; + self + } + + pub fn user_content_manager(mut self, user_content_manager: UserContentManager) -> Self { + self.user_content_manager = user_content_manager; + self + } + + pub fn protocol_registry(mut self, protocol_registry: ProtocolRegistry) -> Self { + self.protocol_registry = protocol_registry; + self + } + + #[cfg(feature = "webxr")] + pub fn webxr_registry(mut self, webxr_registry: Box<dyn webxr::WebXrRegistry>) -> Self { + self.webxr_registry = webxr_registry; + self + } +} diff --git a/components/servo/tests/common/mod.rs b/components/servo/tests/common/mod.rs index 9f6b3f03449..8c00826a0d8 100644 --- a/components/servo/tests/common/mod.rs +++ b/components/servo/tests/common/mod.rs @@ -8,13 +8,12 @@ use std::sync::{Arc, OnceLock}; use std::time::Duration; use anyhow::Error; -use compositing::windowing::EmbedderMethods; use compositing_traits::rendering_context::{RenderingContext, SoftwareRenderingContext}; use crossbeam_channel::{Receiver, Sender, unbounded}; use dpi::PhysicalSize; use embedder_traits::EventLoopWaker; use parking_lot::Mutex; -use servo::Servo; +use servo::{Servo, ServoBuilder}; pub struct ServoTest { servo: Servo, @@ -42,14 +41,6 @@ impl ServoTest { assert!(rendering_context.make_current().is_ok()); #[derive(Clone)] - struct EmbedderMethodsImpl(Arc<AtomicBool>); - impl EmbedderMethods for EmbedderMethodsImpl { - fn create_event_loop_waker(&mut self) -> Box<dyn embedder_traits::EventLoopWaker> { - Box::new(EventLoopWakerImpl(self.0.clone())) - } - } - - #[derive(Clone)] struct EventLoopWakerImpl(Arc<AtomicBool>); impl EventLoopWaker for EventLoopWakerImpl { fn clone_box(&self) -> Box<dyn EventLoopWaker> { @@ -62,13 +53,9 @@ impl ServoTest { } let user_event_triggered = Arc::new(AtomicBool::new(false)); - let servo = Servo::new( - Default::default(), - Default::default(), - rendering_context.clone(), - Box::new(EmbedderMethodsImpl(user_event_triggered)), - Default::default(), - ); + let servo = ServoBuilder::new(rendering_context.clone()) + .event_loop_waker(Box::new(EventLoopWakerImpl(user_event_triggered))) + .build(); Self { servo } } diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 11952f60cb6..5f1171859dc 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -92,7 +92,7 @@ pub enum Cursor { pub trait EventLoopWaker: 'static + Send { fn clone_box(&self) -> Box<dyn EventLoopWaker>; - fn wake(&self); + fn wake(&self) {} } impl Clone for Box<dyn EventLoopWaker> { diff --git a/components/webxr/Cargo.toml b/components/webxr/Cargo.toml index 809e8483bd4..49315ac41db 100644 --- a/components/webxr/Cargo.toml +++ b/components/webxr/Cargo.toml @@ -26,6 +26,7 @@ openxr-api = ["angle", "openxr", "winapi", "wio", "surfman/sm-angle-default"] [dependencies] crossbeam-channel = { workspace = true } +embedder_traits = { workspace = true } euclid = { workspace = true } glow = { workspace = true } log = { workspace = true } diff --git a/components/webxr/lib.rs b/components/webxr/lib.rs index 862d8e9814e..ba3bd37f118 100644 --- a/components/webxr/lib.rs +++ b/components/webxr/lib.rs @@ -19,3 +19,8 @@ pub type MainThreadRegistry = webxr_api::MainThreadRegistry<surfman_layer_manage pub type Discovery = Box<dyn webxr_api::DiscoveryAPI<SurfmanGL>>; pub(crate) mod gl_utils; + +pub trait WebXrRegistry { + /// Register services with a WebXR Registry. + fn register(&self, _: &mut MainThreadRegistry) {} +} diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 880178aaff8..4dde169fb4b 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -11,16 +11,14 @@ use std::rc::Rc; use std::time::Instant; use std::{env, fs}; +use ::servo::ServoBuilder; use log::{info, trace, warn}; +use net::protocols::ProtocolRegistry; +use servo::EventLoopWaker; use servo::config::opts::Opts; use servo::config::prefs::Preferences; -use servo::servo_config::pref; use servo::servo_url::ServoUrl; use servo::user_content_manager::{UserContentManager, UserScript}; -use servo::webxr::glwindow::GlWindowDiscovery; -#[cfg(target_os = "windows")] -use servo::webxr::openxr::{AppInfo, OpenXrDiscovery}; -use servo::{EventLoopWaker, Servo}; use url::Url; use winit::application::ApplicationHandler; use winit::event::WindowEvent; @@ -32,8 +30,9 @@ use super::events_loop::{EventsLoop, WakerEvent}; use super::minibrowser::{Minibrowser, MinibrowserEvent}; use super::{headed_window, headless_window}; use crate::desktop::app_state::RunningAppState; -use crate::desktop::embedder::{EmbedderCallbacks, XrDiscovery}; +use crate::desktop::protocols; use crate::desktop::tracing::trace_winit_event; +use crate::desktop::webxr::XrDiscoveryWebXrRegistry; use crate::desktop::window_trait::WindowPortsMethods; use crate::parser::{get_default_url, location_bar_input_to_url}; use crate::prefs::ServoShellPreferences; @@ -115,26 +114,6 @@ impl App { self.suspended.set(false); let (_, window) = self.windows.iter().next().unwrap(); - let xr_discovery = if pref!(dom_webxr_openxr_enabled) && !headless { - #[cfg(target_os = "windows")] - let openxr = { - let app_info = AppInfo::new("Servoshell", 0, "Servo", 0); - Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info))) - }; - #[cfg(not(target_os = "windows"))] - let openxr = None; - - openxr - } else if pref!(dom_webxr_glwindow_enabled) && !headless { - let window = window.new_glwindow(event_loop.unwrap()); - Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(window))) - } else { - None - }; - - // Implements embedder methods, used by libservo and constellation. - let embedder = Box::new(EmbedderCallbacks::new(self.waker.clone(), xr_discovery)); - let mut user_content_manager = UserContentManager::new(); for script in load_userscripts(self.servoshell_preferences.userscripts_directory.as_deref()) .expect("Loading userscripts failed") @@ -142,13 +121,32 @@ impl App { user_content_manager.add_script(script); } - let servo = Servo::new( - self.opts.clone(), - self.preferences.clone(), - window.rendering_context(), - embedder, - user_content_manager, + let mut protocol_registry = ProtocolRegistry::default(); + protocol_registry.register( + "urlinfo", + protocols::urlinfo::UrlInfoProtocolHander::default(), + ); + protocol_registry.register("servo", protocols::servo::ServoProtocolHandler::default()); + protocol_registry.register( + "resource", + protocols::resource::ResourceProtocolHandler::default(), ); + + let servo_builder = ServoBuilder::new(window.rendering_context()) + .opts(self.opts.clone()) + .preferences(self.preferences.clone()) + .user_content_manager(user_content_manager) + .protocol_registry(protocol_registry) + .event_loop_waker(self.waker.clone()); + + #[cfg(feature = "webxr")] + let servo_builder = servo_builder.webxr_registry(XrDiscoveryWebXrRegistry::new_boxed( + window.clone(), + event_loop, + &self.preferences, + )); + + let servo = servo_builder.build(); servo.setup_logging(); let running_state = Rc::new(RunningAppState::new( diff --git a/ports/servoshell/desktop/embedder.rs b/ports/servoshell/desktop/embedder.rs deleted file mode 100644 index 9c8563b04b4..00000000000 --- a/ports/servoshell/desktop/embedder.rs +++ /dev/null @@ -1,71 +0,0 @@ -/* 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/. */ - -//! Implements the global methods required by Servo (not window/gl/compositor related). - -use net::protocols::ProtocolRegistry; -use servo::compositing::windowing::EmbedderMethods; -use servo::servo_config::pref; -use servo::webxr::glwindow::GlWindowDiscovery; -#[cfg(target_os = "windows")] -use servo::webxr::openxr::OpenXrDiscovery; -use servo::{EmbedderProxy, EventLoopWaker}; - -use crate::desktop::protocols::{resource, servo as servo_handler, urlinfo}; - -pub enum XrDiscovery { - GlWindow(GlWindowDiscovery), - #[cfg(target_os = "windows")] - OpenXr(OpenXrDiscovery), -} - -pub struct EmbedderCallbacks { - event_loop_waker: Box<dyn EventLoopWaker>, - xr_discovery: Option<XrDiscovery>, -} - -impl EmbedderCallbacks { - pub fn new( - event_loop_waker: Box<dyn EventLoopWaker>, - xr_discovery: Option<XrDiscovery>, - ) -> EmbedderCallbacks { - EmbedderCallbacks { - event_loop_waker, - xr_discovery, - } - } -} - -impl EmbedderMethods for EmbedderCallbacks { - fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> { - self.event_loop_waker.clone() - } - - #[cfg(feature = "webxr")] - fn register_webxr( - &mut self, - xr: &mut servo::webxr::MainThreadRegistry, - _embedder_proxy: EmbedderProxy, - ) { - use servo::webxr::headless::HeadlessMockDiscovery; - - if pref!(dom_webxr_test) { - xr.register_mock(HeadlessMockDiscovery::default()); - } else if let Some(xr_discovery) = self.xr_discovery.take() { - match xr_discovery { - XrDiscovery::GlWindow(discovery) => xr.register(discovery), - #[cfg(target_os = "windows")] - XrDiscovery::OpenXr(discovery) => xr.register(discovery), - } - } - } - - fn get_protocol_handlers(&self) -> ProtocolRegistry { - let mut registry = ProtocolRegistry::default(); - registry.register("urlinfo", urlinfo::UrlInfoProtocolHander::default()); - registry.register("servo", servo_handler::ServoProtocolHandler::default()); - registry.register("resource", resource::ResourceProtocolHandler::default()); - registry - } -} diff --git a/ports/servoshell/desktop/mod.rs b/ports/servoshell/desktop/mod.rs index ffa1353906b..15c4301373f 100644 --- a/ports/servoshell/desktop/mod.rs +++ b/ports/servoshell/desktop/mod.rs @@ -10,7 +10,6 @@ mod app_state; pub(crate) mod cli; mod dialog; mod egui_glue; -mod embedder; pub(crate) mod events_loop; mod gamepad; pub mod geometry; @@ -20,4 +19,5 @@ mod keyutils; mod minibrowser; mod protocols; mod tracing; +mod webxr; mod window_trait; diff --git a/ports/servoshell/desktop/webxr.rs b/ports/servoshell/desktop/webxr.rs new file mode 100644 index 00000000000..8f85d6b08b2 --- /dev/null +++ b/ports/servoshell/desktop/webxr.rs @@ -0,0 +1,78 @@ +/* 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::RefCell; +use std::rc::Rc; + +use servo::config::pref; +use servo::config::prefs::Preferences; +use servo::webxr::WebXrRegistry; +use servo::webxr::glwindow::GlWindowDiscovery; +#[cfg(target_os = "windows")] +use servo::webxr::openxr::{AppInfo, OpenXrDiscovery}; +use winit::event_loop::ActiveEventLoop; + +use super::window_trait::WindowPortsMethods; + +#[cfg(feature = "webxr")] +enum XrDiscovery { + GlWindow(GlWindowDiscovery), + #[cfg(target_os = "windows")] + OpenXr(OpenXrDiscovery), +} + +#[cfg(feature = "webxr")] +pub(crate) struct XrDiscoveryWebXrRegistry { + xr_discovery: RefCell<Option<XrDiscovery>>, +} + +impl XrDiscoveryWebXrRegistry { + pub(crate) fn new_boxed( + window: Rc<dyn WindowPortsMethods>, + event_loop: Option<&ActiveEventLoop>, + preferences: &Preferences, + ) -> Box<Self> { + let Some(event_loop) = event_loop else { + return Box::new(Self { + xr_discovery: RefCell::new(None), + }); + }; + + let xr_discovery = if preferences.dom_webxr_openxr_enabled { + #[cfg(target_os = "windows")] + { + let app_info = AppInfo::new("Servoshell", 0, "Servo", 0); + Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info))) + } + #[cfg(not(target_os = "windows"))] + None + } else if preferences.dom_webxr_glwindow_enabled { + let window = window.new_glwindow(event_loop); + Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(window))) + } else { + None + }; + + Box::new(Self { + xr_discovery: RefCell::new(xr_discovery), + }) + } +} + +#[cfg(feature = "webxr")] +impl WebXrRegistry for XrDiscoveryWebXrRegistry { + fn register(&self, xr: &mut servo::webxr::MainThreadRegistry) { + use servo::webxr::headless::HeadlessMockDiscovery; + + if pref!(dom_webxr_test) { + xr.register_mock(HeadlessMockDiscovery::default()); + } else if let Some(xr_discovery) = self.xr_discovery.take() { + match xr_discovery { + XrDiscovery::GlWindow(discovery) => xr.register(discovery), + #[cfg(target_os = "windows")] + XrDiscovery::OpenXr(discovery) => xr.register(discovery), + } + } + } +} diff --git a/ports/servoshell/egl/android.rs b/ports/servoshell/egl/android.rs index 0cb9c36fdce..5a3047c8542 100644 --- a/ports/servoshell/egl/android.rs +++ b/ports/servoshell/egl/android.rs @@ -20,11 +20,10 @@ use raw_window_handle::{ AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle, }; use servo::{ - AlertResponse, LoadStatus, MediaSessionActionType, PermissionRequest, SimpleDialog, WebView, -}; -use simpleservo::{ - APP, DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState, + AlertResponse, EventLoopWaker, LoadStatus, MediaSessionActionType, PermissionRequest, + SimpleDialog, WebView, }; +use simpleservo::{APP, DeviceIntRect, InitOptions, InputMethodType, MediaSessionPlaybackState}; use super::app_state::{Coordinates, RunningAppState}; use super::host_trait::HostTrait; diff --git a/ports/servoshell/egl/android/simpleservo.rs b/ports/servoshell/egl/android/simpleservo.rs index 5bd484a5c84..4f7e35d3923 100644 --- a/ports/servoshell/egl/android/simpleservo.rs +++ b/ports/servoshell/egl/android/simpleservo.rs @@ -8,18 +8,14 @@ use std::rc::Rc; use dpi::PhysicalSize; use raw_window_handle::{DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle}; -/// The EventLoopWaker::wake function will be called from any thread. -/// It will be called to notify embedder that some events are available, -/// and that perform_updates need to be called -pub use servo::EventLoopWaker; pub use servo::webrender_api::units::DeviceIntRect; -use servo::{self, Servo, resources}; +use servo::{self, EventLoopWaker, ServoBuilder, resources}; pub use servo::{InputMethodType, MediaSessionPlaybackState, WindowRenderingContext}; use crate::egl::android::resources::ResourceReaderInstance; -use crate::egl::app_state::{ - Coordinates, RunningAppState, ServoEmbedderCallbacks, ServoWindowCallbacks, -}; +#[cfg(feature = "webxr")] +use crate::egl::app_state::XrDiscoveryWebXrRegistry; +use crate::egl::app_state::{Coordinates, RunningAppState, ServoWindowCallbacks}; use crate::egl::host_trait::HostTrait; use crate::prefs::{ArgumentParsingResult, parse_command_line_arguments}; @@ -85,26 +81,22 @@ pub fn init( RefCell::new(init_opts.coordinates), )); - let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( - waker, - #[cfg(feature = "webxr")] - init_opts.xr_discovery, - )); + let servo_builder = ServoBuilder::new(rendering_context.clone()) + .opts(opts) + .preferences(preferences) + .event_loop_waker(waker); - let servo = Servo::new( - opts, - preferences, - rendering_context.clone(), - embedder_callbacks, - Default::default(), - ); + #[cfg(feature = "webxr")] + let servo_builder = servo_builder.webxr_registry(Box::new(XrDiscoveryWebXrRegistry::new( + init_opts.xr_discovery, + ))); APP.with(|app| { let app_state = RunningAppState::new( init_opts.url, init_opts.density, rendering_context, - servo, + servo_builder.build(), window_callbacks, servoshell_preferences, ); diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 8207fb3f2fb..a65ed7424f4 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -11,18 +11,16 @@ use keyboard_types::{CompositionEvent, CompositionState}; use log::{debug, error, info, warn}; use raw_window_handle::{RawWindowHandle, WindowHandle}; use servo::base::id::WebViewId; -use servo::compositing::windowing::EmbedderMethods; use servo::euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::ScrollLocation; use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel}; use servo::{ - AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent, - InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, - MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, - NavigationRequest, PermissionRequest, RenderingContext, ScreenGeometry, Servo, ServoDelegate, - ServoError, SimpleDialog, TouchEvent, TouchEventType, TouchId, WebView, WebViewBuilder, - WebViewDelegate, WindowRenderingContext, + AllowOrDenyRequest, ContextMenuResult, ImeEvent, InputEvent, InputMethodType, Key, KeyState, + KeyboardEvent, LoadStatus, MediaSessionActionType, MediaSessionEvent, MouseButton, + MouseButtonAction, MouseButtonEvent, MouseMoveEvent, NavigationRequest, PermissionRequest, + RenderingContext, ScreenGeometry, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEvent, + TouchEventType, TouchId, WebView, WebViewBuilder, WebViewDelegate, WindowRenderingContext, }; use url::Url; @@ -682,38 +680,24 @@ impl RunningAppState { } } -pub(super) struct ServoEmbedderCallbacks { - waker: Box<dyn EventLoopWaker>, - #[cfg(feature = "webxr")] - xr_discovery: Option<servo::webxr::Discovery>, +#[cfg(feature = "webxr")] +pub(crate) struct XrDiscoveryWebXrRegistry { + xr_discovery: RefCell<Option<servo::webxr::Discovery>>, } -impl ServoEmbedderCallbacks { - pub(super) fn new( - waker: Box<dyn EventLoopWaker>, - #[cfg(feature = "webxr")] xr_discovery: Option<servo::webxr::Discovery>, - ) -> Self { +#[cfg(feature = "webxr")] +impl XrDiscoveryWebXrRegistry { + pub(crate) fn new(xr_discovery: Option<servo::webxr::Discovery>) -> Self { Self { - waker, - #[cfg(feature = "webxr")] - xr_discovery, + xr_discovery: RefCell::new(xr_discovery), } } } -impl EmbedderMethods for ServoEmbedderCallbacks { - fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> { - debug!("EmbedderMethods::create_event_loop_waker"); - self.waker.clone() - } - - #[cfg(feature = "webxr")] - fn register_webxr( - &mut self, - registry: &mut servo::webxr::MainThreadRegistry, - _embedder_proxy: EmbedderProxy, - ) { - debug!("EmbedderMethods::register_xr"); +#[cfg(feature = "webxr")] +impl servo::webxr::WebXrRegistry for XrDiscoveryWebXrRegistry { + fn register(&self, registry: &mut servo::webxr::MainThreadRegistry) { + debug!("XrDiscoveryWebXrRegistry::register"); if let Some(discovery) = self.xr_discovery.take() { registry.register(discovery); } diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index fbdbe5395a1..236f1d842da 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -22,10 +22,9 @@ use ohos_ime::{AttachOptions, Ime, ImeProxy, RawTextEditorProxy}; use ohos_ime_sys::types::InputMethod_EnterKeyType; use servo::style::Zero; use servo::{ - AlertResponse, InputMethodType, LoadStatus, MediaSessionPlaybackState, PermissionRequest, - SimpleDialog, WebView, + AlertResponse, EventLoopWaker, InputMethodType, LoadStatus, MediaSessionPlaybackState, + PermissionRequest, SimpleDialog, WebView, }; -use simpleservo::EventLoopWaker; use xcomponent_sys::{ OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent, OH_NativeXComponent_GetKeyEventAction, OH_NativeXComponent_GetKeyEventCode, diff --git a/ports/servoshell/egl/ohos/simpleservo.rs b/ports/servoshell/egl/ohos/simpleservo.rs index 3bb1191f3f6..9815c0fe4fd 100644 --- a/ports/servoshell/egl/ohos/simpleservo.rs +++ b/ports/servoshell/egl/ohos/simpleservo.rs @@ -14,16 +14,10 @@ use raw_window_handle::{ DisplayHandle, OhosDisplayHandle, OhosNdkWindowHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, }; -/// The EventLoopWaker::wake function will be called from any thread. -/// It will be called to notify embedder that some events are available, -/// and that perform_updates need to be called -pub use servo::EventLoopWaker; -use servo::{self, Servo, WindowRenderingContext, resources}; +use servo::{self, EventLoopWaker, ServoBuilder, WindowRenderingContext, resources}; use xcomponent_sys::OH_NativeXComponent; -use crate::egl::app_state::{ - Coordinates, RunningAppState, ServoEmbedderCallbacks, ServoWindowCallbacks, -}; +use crate::egl::app_state::{Coordinates, RunningAppState, ServoWindowCallbacks}; use crate::egl::host_trait::HostTrait; use crate::egl::ohos::InitOpts; use crate::egl::ohos::resources::ResourceReaderInstance; @@ -128,19 +122,11 @@ pub fn init( RefCell::new(coordinates), )); - let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( - waker, - #[cfg(feature = "webxr")] - None, - )); - - let servo = Servo::new( - opts, - preferences, - rendering_context.clone(), - embedder_callbacks, - Default::default(), - ); + let servo = ServoBuilder::new(rendering_context.clone()) + .opts(opts) + .preferences(preferences) + .event_loop_waker(waker) + .build(); let app_state = RunningAppState::new( Some(options.url), |