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

1
Cargo.lock generated
View file

@ -8595,6 +8595,7 @@ name = "webxr"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"embedder_traits",
"euclid", "euclid",
"glow", "glow",
"log", "log",

View file

@ -2,11 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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. /// Various debug and profiling flags that WebRender supports.
#[derive(Clone)] #[derive(Clone)]
pub enum WebRenderDebugOption { pub enum WebRenderDebugOption {
@ -14,23 +9,3 @@ pub enum WebRenderDebugOption {
TextureCacheDebug, TextureCacheDebug,
RenderTargetDebug, 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()
}
}

View file

@ -5,10 +5,10 @@ use std::cell::RefCell;
use std::error::Error; use std::error::Error;
use std::rc::Rc; use std::rc::Rc;
use compositing::windowing::EmbedderMethods;
use euclid::{Scale, Size2D}; use euclid::{Scale, Size2D};
use servo::{ use servo::{
RenderingContext, Servo, TouchEventType, WebView, WebViewBuilder, WindowRenderingContext, RenderingContext, Servo, ServoBuilder, TouchEventType, WebView, WebViewBuilder,
WindowRenderingContext,
}; };
use tracing::warn; use tracing::warn;
use url::Url; use url::Url;
@ -95,15 +95,9 @@ impl ApplicationHandler<WakerEvent> for App {
let _ = rendering_context.make_current(); let _ = rendering_context.make_current();
let servo = Servo::new( let servo = ServoBuilder::new(rendering_context.clone())
Default::default(), .event_loop_waker(Box::new(waker.clone()))
Default::default(), .build();
rendering_context.clone(),
Box::new(EmbedderDelegate {
waker: waker.clone(),
}),
Default::default(),
);
servo.setup_logging(); servo.setup_logging();
let app_state = Rc::new(AppState { 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)] #[derive(Clone)]
struct Waker(winit::event_loop::EventLoopProxy<WakerEvent>); struct Waker(winit::event_loop::EventLoopProxy<WakerEvent>);
#[derive(Debug)] #[derive(Debug)]

View file

@ -42,7 +42,6 @@ use canvas::WebGLComm;
use canvas::canvas_paint_thread::CanvasPaintThread; use canvas::canvas_paint_thread::CanvasPaintThread;
use canvas_traits::webgl::{GlType, WebGLThreads}; use canvas_traits::webgl::{GlType, WebGLThreads};
use clipboard_delegate::StringRequest; use clipboard_delegate::StringRequest;
use compositing::windowing::EmbedderMethods;
use compositing::{IOCompositor, InitialCompositorState}; use compositing::{IOCompositor, InitialCompositorState};
pub use compositing_traits::rendering_context::{ pub use compositing_traits::rendering_context::{
OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext, OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext,
@ -247,26 +246,18 @@ impl webrender_api::RenderNotifier for RenderNotifier {
impl Servo { impl Servo {
#[cfg_attr( #[cfg_attr(
feature = "tracing", feature = "tracing",
tracing::instrument( tracing::instrument(skip(builder), fields(servo_profiling = true), level = "trace",)
skip(preferences, rendering_context, embedder),
fields(servo_profiling = true),
level = "trace",
)
)] )]
pub fn new( fn new(builder: ServoBuilder) -> Self {
opts: Opts,
preferences: Preferences,
rendering_context: Rc<dyn RenderingContext>,
mut embedder: Box<dyn EmbedderMethods>,
user_content_manager: UserContentManager,
) -> Self {
// Global configuration options, parsed from the command line. // 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(); let opts = opts::get();
// Set the preferences globally. // Set the preferences globally.
// TODO: It would be better to make these private to a particular Servo instance. // 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; use std::sync::atomic::Ordering;
@ -282,6 +273,7 @@ impl Servo {
} }
// Get GL bindings // Get GL bindings
let rendering_context = builder.rendering_context;
let webrender_gl = rendering_context.gleam_gl_api(); let webrender_gl = rendering_context.gleam_gl_api();
// Make sure the gl context is made current. // 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 // the client window and the compositor. This channel is unique because
// messages to client may need to pump a platform-specific event loop // messages to client may need to pump a platform-specific event loop
// to deliver the message. // 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) = let (compositor_proxy, compositor_receiver) =
create_compositor_channel(event_loop_waker.clone()); create_compositor_channel(event_loop_waker.clone());
let (embedder_proxy, embedder_receiver) = create_embedder_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"); .expect("Failed to create WebXR device registry");
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
if pref!(dom_webxr_enabled) { 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")] #[cfg(feature = "webgpu")]
@ -447,7 +439,7 @@ impl Servo {
// Create the constellation, which maintains the engine pipelines, including script and // Create the constellation, which maintains the engine pipelines, including script and
// layout, as well as the navigation context. // layout, as well as the navigation context.
let mut protocols = ProtocolRegistry::with_internal_protocols(); let mut protocols = ProtocolRegistry::with_internal_protocols();
protocols.merge(embedder.get_protocol_handlers()); protocols.merge(builder.protocol_registry);
let constellation_chan = create_constellation( let constellation_chan = create_constellation(
opts.config_dir.clone(), opts.config_dir.clone(),
@ -465,7 +457,7 @@ impl Servo {
#[cfg(feature = "webgpu")] #[cfg(feature = "webgpu")]
wgpu_image_map, wgpu_image_map,
protocols, protocols,
user_content_manager, builder.user_content_manager,
); );
if cfg!(feature = "webdriver") { if cfg!(feature = "webdriver") {
@ -1204,3 +1196,77 @@ fn create_sandbox() {
fn create_sandbox() { fn create_sandbox() {
panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android."); 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
}
}

View file

@ -8,13 +8,12 @@ use std::sync::{Arc, OnceLock};
use std::time::Duration; use std::time::Duration;
use anyhow::Error; use anyhow::Error;
use compositing::windowing::EmbedderMethods;
use compositing_traits::rendering_context::{RenderingContext, SoftwareRenderingContext}; use compositing_traits::rendering_context::{RenderingContext, SoftwareRenderingContext};
use crossbeam_channel::{Receiver, Sender, unbounded}; use crossbeam_channel::{Receiver, Sender, unbounded};
use dpi::PhysicalSize; use dpi::PhysicalSize;
use embedder_traits::EventLoopWaker; use embedder_traits::EventLoopWaker;
use parking_lot::Mutex; use parking_lot::Mutex;
use servo::Servo; use servo::{Servo, ServoBuilder};
pub struct ServoTest { pub struct ServoTest {
servo: Servo, servo: Servo,
@ -41,14 +40,6 @@ impl ServoTest {
); );
assert!(rendering_context.make_current().is_ok()); 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)] #[derive(Clone)]
struct EventLoopWakerImpl(Arc<AtomicBool>); struct EventLoopWakerImpl(Arc<AtomicBool>);
impl EventLoopWaker for EventLoopWakerImpl { impl EventLoopWaker for EventLoopWakerImpl {
@ -62,13 +53,9 @@ impl ServoTest {
} }
let user_event_triggered = Arc::new(AtomicBool::new(false)); let user_event_triggered = Arc::new(AtomicBool::new(false));
let servo = Servo::new( let servo = ServoBuilder::new(rendering_context.clone())
Default::default(), .event_loop_waker(Box::new(EventLoopWakerImpl(user_event_triggered)))
Default::default(), .build();
rendering_context.clone(),
Box::new(EmbedderMethodsImpl(user_event_triggered)),
Default::default(),
);
Self { servo } Self { servo }
} }

View file

@ -92,7 +92,7 @@ pub enum Cursor {
pub trait EventLoopWaker: 'static + Send { pub trait EventLoopWaker: 'static + Send {
fn clone_box(&self) -> Box<dyn EventLoopWaker>; fn clone_box(&self) -> Box<dyn EventLoopWaker>;
fn wake(&self); fn wake(&self) {}
} }
impl Clone for Box<dyn EventLoopWaker> { impl Clone for Box<dyn EventLoopWaker> {

View file

@ -26,6 +26,7 @@ openxr-api = ["angle", "openxr", "winapi", "wio", "surfman/sm-angle-default"]
[dependencies] [dependencies]
crossbeam-channel = { workspace = true } crossbeam-channel = { workspace = true }
embedder_traits = { workspace = true }
euclid = { workspace = true } euclid = { workspace = true }
glow = { workspace = true } glow = { workspace = true }
log = { workspace = true } log = { workspace = true }

View file

@ -19,3 +19,8 @@ pub type MainThreadRegistry = webxr_api::MainThreadRegistry<surfman_layer_manage
pub type Discovery = Box<dyn webxr_api::DiscoveryAPI<SurfmanGL>>; pub type Discovery = Box<dyn webxr_api::DiscoveryAPI<SurfmanGL>>;
pub(crate) mod gl_utils; pub(crate) mod gl_utils;
pub trait WebXrRegistry {
/// Register services with a WebXR Registry.
fn register(&self, _: &mut MainThreadRegistry) {}
}

View file

@ -11,16 +11,14 @@ use std::rc::Rc;
use std::time::Instant; use std::time::Instant;
use std::{env, fs}; use std::{env, fs};
use ::servo::ServoBuilder;
use log::{info, trace, warn}; use log::{info, trace, warn};
use net::protocols::ProtocolRegistry;
use servo::EventLoopWaker;
use servo::config::opts::Opts; use servo::config::opts::Opts;
use servo::config::prefs::Preferences; use servo::config::prefs::Preferences;
use servo::servo_config::pref;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::user_content_manager::{UserContentManager, UserScript}; 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 url::Url;
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::event::WindowEvent; use winit::event::WindowEvent;
@ -32,8 +30,9 @@ use super::events_loop::{EventsLoop, WakerEvent};
use super::minibrowser::{Minibrowser, MinibrowserEvent}; use super::minibrowser::{Minibrowser, MinibrowserEvent};
use super::{headed_window, headless_window}; use super::{headed_window, headless_window};
use crate::desktop::app_state::RunningAppState; 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::tracing::trace_winit_event;
use crate::desktop::webxr::XrDiscoveryWebXrRegistry;
use crate::desktop::window_trait::WindowPortsMethods; use crate::desktop::window_trait::WindowPortsMethods;
use crate::parser::{get_default_url, location_bar_input_to_url}; use crate::parser::{get_default_url, location_bar_input_to_url};
use crate::prefs::ServoShellPreferences; use crate::prefs::ServoShellPreferences;
@ -115,26 +114,6 @@ impl App {
self.suspended.set(false); self.suspended.set(false);
let (_, window) = self.windows.iter().next().unwrap(); 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(); let mut user_content_manager = UserContentManager::new();
for script in load_userscripts(self.servoshell_preferences.userscripts_directory.as_deref()) for script in load_userscripts(self.servoshell_preferences.userscripts_directory.as_deref())
.expect("Loading userscripts failed") .expect("Loading userscripts failed")
@ -142,13 +121,32 @@ impl App {
user_content_manager.add_script(script); user_content_manager.add_script(script);
} }
let servo = Servo::new( let mut protocol_registry = ProtocolRegistry::default();
self.opts.clone(), protocol_registry.register(
self.preferences.clone(), "urlinfo",
window.rendering_context(), protocols::urlinfo::UrlInfoProtocolHander::default(),
embedder,
user_content_manager,
); );
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(); servo.setup_logging();
let running_state = Rc::new(RunningAppState::new( 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; pub(crate) mod cli;
mod dialog; mod dialog;
mod egui_glue; mod egui_glue;
mod embedder;
pub(crate) mod events_loop; pub(crate) mod events_loop;
mod gamepad; mod gamepad;
pub mod geometry; pub mod geometry;
@ -20,4 +19,5 @@ mod keyutils;
mod minibrowser; mod minibrowser;
mod protocols; mod protocols;
mod tracing; mod tracing;
mod webxr;
mod window_trait; 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),
}
}
}
}

View file

@ -20,11 +20,10 @@ use raw_window_handle::{
AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle, AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
}; };
use servo::{ use servo::{
AlertResponse, LoadStatus, MediaSessionActionType, PermissionRequest, SimpleDialog, WebView, AlertResponse, EventLoopWaker, LoadStatus, MediaSessionActionType, PermissionRequest,
}; SimpleDialog, WebView,
use simpleservo::{
APP, DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState,
}; };
use simpleservo::{APP, DeviceIntRect, InitOptions, InputMethodType, MediaSessionPlaybackState};
use super::app_state::{Coordinates, RunningAppState}; use super::app_state::{Coordinates, RunningAppState};
use super::host_trait::HostTrait; use super::host_trait::HostTrait;

View file

@ -8,18 +8,14 @@ use std::rc::Rc;
use dpi::PhysicalSize; use dpi::PhysicalSize;
use raw_window_handle::{DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle}; 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; pub use servo::webrender_api::units::DeviceIntRect;
use servo::{self, Servo, resources}; use servo::{self, EventLoopWaker, ServoBuilder, resources};
pub use servo::{InputMethodType, MediaSessionPlaybackState, WindowRenderingContext}; pub use servo::{InputMethodType, MediaSessionPlaybackState, WindowRenderingContext};
use crate::egl::android::resources::ResourceReaderInstance; use crate::egl::android::resources::ResourceReaderInstance;
use crate::egl::app_state::{ #[cfg(feature = "webxr")]
Coordinates, RunningAppState, ServoEmbedderCallbacks, ServoWindowCallbacks, use crate::egl::app_state::XrDiscoveryWebXrRegistry;
}; use crate::egl::app_state::{Coordinates, RunningAppState, ServoWindowCallbacks};
use crate::egl::host_trait::HostTrait; use crate::egl::host_trait::HostTrait;
use crate::prefs::{ArgumentParsingResult, parse_command_line_arguments}; use crate::prefs::{ArgumentParsingResult, parse_command_line_arguments};
@ -85,26 +81,22 @@ pub fn init(
RefCell::new(init_opts.coordinates), RefCell::new(init_opts.coordinates),
)); ));
let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( let servo_builder = ServoBuilder::new(rendering_context.clone())
waker, .opts(opts)
#[cfg(feature = "webxr")] .preferences(preferences)
init_opts.xr_discovery, .event_loop_waker(waker);
));
let servo = Servo::new( #[cfg(feature = "webxr")]
opts, let servo_builder = servo_builder.webxr_registry(Box::new(XrDiscoveryWebXrRegistry::new(
preferences, init_opts.xr_discovery,
rendering_context.clone(), )));
embedder_callbacks,
Default::default(),
);
APP.with(|app| { APP.with(|app| {
let app_state = RunningAppState::new( let app_state = RunningAppState::new(
init_opts.url, init_opts.url,
init_opts.density, init_opts.density,
rendering_context, rendering_context,
servo, servo_builder.build(),
window_callbacks, window_callbacks,
servoshell_preferences, servoshell_preferences,
); );

View file

@ -11,18 +11,16 @@ use keyboard_types::{CompositionEvent, CompositionState};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use raw_window_handle::{RawWindowHandle, WindowHandle}; use raw_window_handle::{RawWindowHandle, WindowHandle};
use servo::base::id::WebViewId; use servo::base::id::WebViewId;
use servo::compositing::windowing::EmbedderMethods;
use servo::euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use servo::euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::ScrollLocation; use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel}; use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::{ use servo::{
AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent, AllowOrDenyRequest, ContextMenuResult, ImeEvent, InputEvent, InputMethodType, Key, KeyState,
InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, KeyboardEvent, LoadStatus, MediaSessionActionType, MediaSessionEvent, MouseButton,
MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, NavigationRequest, PermissionRequest,
NavigationRequest, PermissionRequest, RenderingContext, ScreenGeometry, Servo, ServoDelegate, RenderingContext, ScreenGeometry, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEvent,
ServoError, SimpleDialog, TouchEvent, TouchEventType, TouchId, WebView, WebViewBuilder, TouchEventType, TouchId, WebView, WebViewBuilder, WebViewDelegate, WindowRenderingContext,
WebViewDelegate, WindowRenderingContext,
}; };
use url::Url; use url::Url;
@ -682,38 +680,24 @@ impl RunningAppState {
} }
} }
pub(super) struct ServoEmbedderCallbacks { #[cfg(feature = "webxr")]
waker: Box<dyn EventLoopWaker>, pub(crate) struct XrDiscoveryWebXrRegistry {
#[cfg(feature = "webxr")] xr_discovery: RefCell<Option<servo::webxr::Discovery>>,
xr_discovery: Option<servo::webxr::Discovery>,
} }
impl ServoEmbedderCallbacks { #[cfg(feature = "webxr")]
pub(super) fn new( impl XrDiscoveryWebXrRegistry {
waker: Box<dyn EventLoopWaker>, pub(crate) fn new(xr_discovery: Option<servo::webxr::Discovery>) -> Self {
#[cfg(feature = "webxr")] xr_discovery: Option<servo::webxr::Discovery>,
) -> Self {
Self { Self {
waker, xr_discovery: RefCell::new(xr_discovery),
#[cfg(feature = "webxr")]
xr_discovery,
} }
} }
} }
impl EmbedderMethods for ServoEmbedderCallbacks { #[cfg(feature = "webxr")]
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> { impl servo::webxr::WebXrRegistry for XrDiscoveryWebXrRegistry {
debug!("EmbedderMethods::create_event_loop_waker"); fn register(&self, registry: &mut servo::webxr::MainThreadRegistry) {
self.waker.clone() debug!("XrDiscoveryWebXrRegistry::register");
}
#[cfg(feature = "webxr")]
fn register_webxr(
&mut self,
registry: &mut servo::webxr::MainThreadRegistry,
_embedder_proxy: EmbedderProxy,
) {
debug!("EmbedderMethods::register_xr");
if let Some(discovery) = self.xr_discovery.take() { if let Some(discovery) = self.xr_discovery.take() {
registry.register(discovery); registry.register(discovery);
} }

View file

@ -22,10 +22,9 @@ use ohos_ime::{AttachOptions, Ime, ImeProxy, RawTextEditorProxy};
use ohos_ime_sys::types::InputMethod_EnterKeyType; use ohos_ime_sys::types::InputMethod_EnterKeyType;
use servo::style::Zero; use servo::style::Zero;
use servo::{ use servo::{
AlertResponse, InputMethodType, LoadStatus, MediaSessionPlaybackState, PermissionRequest, AlertResponse, EventLoopWaker, InputMethodType, LoadStatus, MediaSessionPlaybackState,
SimpleDialog, WebView, PermissionRequest, SimpleDialog, WebView,
}; };
use simpleservo::EventLoopWaker;
use xcomponent_sys::{ use xcomponent_sys::{
OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent, OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent,
OH_NativeXComponent_GetKeyEventAction, OH_NativeXComponent_GetKeyEventCode, OH_NativeXComponent_GetKeyEventAction, OH_NativeXComponent_GetKeyEventCode,

View file

@ -14,16 +14,10 @@ use raw_window_handle::{
DisplayHandle, OhosDisplayHandle, OhosNdkWindowHandle, RawDisplayHandle, RawWindowHandle, DisplayHandle, OhosDisplayHandle, OhosNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
WindowHandle, WindowHandle,
}; };
/// The EventLoopWaker::wake function will be called from any thread. use servo::{self, EventLoopWaker, ServoBuilder, WindowRenderingContext, resources};
/// 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 xcomponent_sys::OH_NativeXComponent; use xcomponent_sys::OH_NativeXComponent;
use crate::egl::app_state::{ use crate::egl::app_state::{Coordinates, RunningAppState, ServoWindowCallbacks};
Coordinates, RunningAppState, ServoEmbedderCallbacks, ServoWindowCallbacks,
};
use crate::egl::host_trait::HostTrait; use crate::egl::host_trait::HostTrait;
use crate::egl::ohos::InitOpts; use crate::egl::ohos::InitOpts;
use crate::egl::ohos::resources::ResourceReaderInstance; use crate::egl::ohos::resources::ResourceReaderInstance;
@ -128,19 +122,11 @@ pub fn init(
RefCell::new(coordinates), RefCell::new(coordinates),
)); ));
let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( let servo = ServoBuilder::new(rendering_context.clone())
waker, .opts(opts)
#[cfg(feature = "webxr")] .preferences(preferences)
None, .event_loop_waker(waker)
)); .build();
let servo = Servo::new(
opts,
preferences,
rendering_context.clone(),
embedder_callbacks,
Default::default(),
);
let app_state = RunningAppState::new( let app_state = RunningAppState::new(
Some(options.url), Some(options.url),