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>
This commit is contained in:
Martin Robinson 2025-04-16 18:58:52 +02:00 committed by GitHub
parent 7a8e75266f
commit d8a7abda69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 252 additions and 271 deletions

View file

@ -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(

View file

@ -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
}
}

View file

@ -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;

View file

@ -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),
}
}
}
}