aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2025-04-16 18:58:52 +0200
committerGitHub <noreply@github.com>2025-04-16 16:58:52 +0000
commitd8a7abda69dc2e03a845cb053c28764babd5b9de (patch)
treebb15a30aa8729eda1feaeec4ea9a9d7294020be7
parent7a8e75266ff2c138f212a301de9774eafb2b3143 (diff)
downloadservo-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.lock1
-rw-r--r--components/compositing/windowing.rs25
-rw-r--r--components/servo/examples/winit_minimal.rs29
-rw-r--r--components/servo/lib.rs104
-rw-r--r--components/servo/tests/common/mod.rs21
-rw-r--r--components/shared/embedder/lib.rs2
-rw-r--r--components/webxr/Cargo.toml1
-rw-r--r--components/webxr/lib.rs5
-rw-r--r--ports/servoshell/desktop/app.rs62
-rw-r--r--ports/servoshell/desktop/embedder.rs71
-rw-r--r--ports/servoshell/desktop/mod.rs2
-rw-r--r--ports/servoshell/desktop/webxr.rs78
-rw-r--r--ports/servoshell/egl/android.rs7
-rw-r--r--ports/servoshell/egl/android/simpleservo.rs34
-rw-r--r--ports/servoshell/egl/app_state.rs48
-rw-r--r--ports/servoshell/egl/ohos.rs5
-rw-r--r--ports/servoshell/egl/ohos/simpleservo.rs28
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),