diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 6be338b266b..8da18bf5151 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -363,33 +363,13 @@ impl IOCompositor { composite_target: CompositeTarget, exit_after_load: bool, convert_mouse_to_touch: bool, - top_level_browsing_context_id: TopLevelBrowsingContextId, version_string: String, ) -> Self { - let embedder_coordinates = window.get_coordinates(); - let mut webviews = WebViewManager::default(); - webviews - .add( - top_level_browsing_context_id, - WebView { - pipeline_id: None, - rect: embedder_coordinates.get_viewport().to_f32(), - }, - ) - .expect("Infallible with a new WebViewManager"); - let msg = ConstellationMsg::WebViewOpened(top_level_browsing_context_id); - if let Err(e) = state.constellation_chan.send(msg) { - warn!("Sending event to constellation failed ({:?}).", e); - } - webviews - .show(top_level_browsing_context_id) - .expect("Infallible due to add"); - let compositor = IOCompositor { embedder_coordinates: window.get_coordinates(), window, port: state.receiver, - webviews, + webviews: WebViewManager::default(), pipeline_details: HashMap::new(), composition_request: CompositionRequest::NoCompositingNecessary, touch_handler: TouchHandler::new(), @@ -1360,7 +1340,11 @@ impl IOCompositor { if self.embedder_coordinates.viewport != old_coords.viewport { let mut transaction = Transaction::new(); - transaction.set_document_view(self.embedder_coordinates.get_viewport()); + let size = self.embedder_coordinates.get_viewport(); + transaction.set_document_view(size); + if let Err(e) = self.rendering_context.resize(size.size().to_untyped()) { + warn!("Failed to resize surface: {e:?}"); + } self.webrender_api .send_transaction(self.webrender_document, transaction); } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index a94eff93f93..dce66be05ca 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -23,7 +23,6 @@ use webrender_api::units::{ DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceRect, }; use webrender_api::ScrollLocation; -use webrender_traits::RenderingContext; #[derive(Clone)] pub enum MouseWindowEvent { @@ -218,8 +217,6 @@ pub trait WindowMethods { /// will want to avoid blocking on UI events, and just /// run the event loop at the vsync interval. fn set_animation_state(&self, _state: AnimationState); - /// Get the [`RenderingContext`] of this Window. - fn rendering_context(&self) -> RenderingContext; } pub trait EmbedderMethods { diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 3be1160133c..178477bf6a4 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -219,11 +219,6 @@ impl webrender_api::RenderNotifier for RenderNotifier { } } -pub struct InitializedServo { - pub servo: Servo, - pub browser_id: TopLevelBrowsingContextId, -} - impl Servo where Window: WindowMethods + 'static + ?Sized, @@ -238,11 +233,12 @@ where )] #[allow(clippy::new_ret_no_self)] pub fn new( + rendering_context: RenderingContext, mut embedder: Box, window: Rc, user_agent: Option, composite_target: CompositeTarget, - ) -> InitializedServo { + ) -> Servo { // Global configuration options, parsed from the command line. let opts = opts::get(); @@ -277,9 +273,6 @@ where .unwrap_or(default_user_agent_string_for(DEFAULT_USER_AGENT).into()), }; - // Initialize surfman - let rendering_context = window.rendering_context(); - // Get GL bindings let webrender_gl = match rendering_context.connection().gl_api() { GLApi::GL => unsafe { gl::GlFns::load_with(|s| rendering_context.get_proc_address(s)) }, @@ -302,7 +295,6 @@ where // Reserving a namespace to create TopLevelBrowsingContextId. PipelineNamespace::install(PipelineNamespaceId(0)); - let top_level_browsing_context_id = TopLevelBrowsingContextId::new(); // Get both endpoints of a special channel for communication between // the client window and the compositor. This channel is unique because @@ -525,21 +517,16 @@ where composite_target, opts.exit_after_load, opts.debug.convert_mouse_to_touch, - top_level_browsing_context_id, embedder.get_version_string().unwrap_or_default(), ); - let servo = Servo { + Servo { compositor, constellation_chan, embedder_receiver, messages_for_embedder: Vec::new(), profiler_enabled: false, _js_engine_setup: js_engine_setup, - }; - InitializedServo { - servo, - browser_id: top_level_browsing_context_id, } } diff --git a/components/shared/base/id.rs b/components/shared/base/id.rs index 47625ae7d44..a20e4d20889 100644 --- a/components/shared/base/id.rs +++ b/components/shared/base/id.rs @@ -282,6 +282,8 @@ thread_local!(pub static TOP_LEVEL_BROWSING_CONTEXT_ID: Cell, + headless: Option>, ) -> Result { let mut device = connection.create_device(adapter)?; let flags = ContextAttributeFlags::ALPHA | @@ -57,21 +57,16 @@ impl RenderingContext { let context_descriptor = device.create_context_descriptor(&context_attributes)?; let mut context = device.create_context(&context_descriptor, None)?; let surface_access = SurfaceAccess::GPUOnly; - let headless = match surface_type { - SurfaceType::Widget { .. } => false, - SurfaceType::Generic { .. } => true, - }; - let surface = device.create_surface(&context, surface_access, surface_type)?; - device - .bind_surface_to_context(&mut context, surface) - .map_err(|(err, mut surface)| { - let _ = device.destroy_surface(&mut context, &mut surface); - err - })?; - - device.make_context_current(&context)?; - - let swap_chain = if headless { + let swap_chain = if let Some(size) = headless { + let surface_type = SurfaceType::Generic { size }; + let surface = device.create_surface(&context, surface_access, surface_type)?; + device + .bind_surface_to_context(&mut context, surface) + .map_err(|(err, mut surface)| { + let _ = device.destroy_surface(&mut context, &mut surface); + err + })?; + device.make_context_current(&context)?; Some(SwapChain::create_attached( &mut device, &mut context, @@ -100,6 +95,20 @@ impl RenderingContext { device.create_surface(context, surface_access, surface_type) } + pub fn bind_surface(&self, surface: Surface) -> Result<(), Error> { + let device = &self.0.device.borrow(); + let context = &mut self.0.context.borrow_mut(); + device + .bind_surface_to_context(context, surface) + .map_err(|(err, mut surface)| { + let _ = device.destroy_surface(context, &mut surface); + err + })?; + + device.make_context_current(context)?; + Ok(()) + } + pub fn destroy_surface(&self, mut surface: Surface) -> Result<(), Error> { let device = &self.0.device.borrow(); let context = &mut self.0.context.borrow_mut(); diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 7f548e894b1..606c3ee9bac 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -4,22 +4,24 @@ //! Application entry point, runs the event loop. -use std::cell::{Cell, RefCell, RefMut}; +use std::cell::Cell; use std::collections::HashMap; use std::rc::Rc; use std::time::Instant; use std::{env, fs}; -use gleam::gl; -use log::{error, info, trace}; +use log::{info, trace}; +use raw_window_handle::HasDisplayHandle; +use servo::base::id::WebViewId; use servo::compositing::windowing::EmbedderEvent; use servo::compositing::CompositeTarget; use servo::config::opts; use servo::embedder_traits::EventLoopWaker; use servo::servo_config::pref; use servo::url::ServoUrl; +use servo::webrender_traits::RenderingContext; use servo::Servo; -use surfman::GLApi; +use surfman::Connection; use webxr::glwindow::GlWindowDiscovery; #[cfg(target_os = "windows")] use webxr::openxr::{AppInfo, OpenXrDiscovery}; @@ -31,6 +33,7 @@ use winit::window::WindowId; use super::events_loop::{EventLoopGuard, EventsLoop, WakerEvent}; use super::minibrowser::Minibrowser; use super::webview::WebViewManager; +use super::{headed_window, headless_window}; use crate::desktop::embedder::{EmbedderCallbacks, XrDiscovery}; use crate::desktop::events_loop::with_current_event_loop; use crate::desktop::tracing::trace_winit_event; @@ -39,16 +42,18 @@ use crate::parser::get_default_url; pub struct App { servo: Option>, - webviews: RefCell>, - event_queue: RefCell>, + webviews: Option>, + event_queue: Vec, suspended: Cell, windows: HashMap>, - minibrowser: Option>, + minibrowser: Option, user_agent: Option, waker: Box, initial_url: ServoUrl, t_start: Instant, t: Instant, + do_not_use_native_titlebar: bool, + device_pixel_ratio_override: Option, } enum Present { @@ -70,19 +75,19 @@ enum PumpResult { impl App { pub fn new( events_loop: &EventsLoop, - window: Rc, user_agent: Option, url: Option, + do_not_use_native_titlebar: bool, + device_pixel_ratio_override: Option, ) -> Self { // Handle browser state. - let webviews = WebViewManager::new(window.clone()); let initial_url = get_default_url(url.as_deref(), env::current_dir().unwrap(), |path| { fs::metadata(path).is_ok() }); let t = Instant::now(); - let mut app = App { - event_queue: RefCell::new(vec![]), - webviews: RefCell::new(webviews), + App { + event_queue: vec![], + webviews: None, servo: None, suspended: Cell::new(false), windows: HashMap::new(), @@ -92,54 +97,80 @@ impl App { initial_url: initial_url.clone(), t_start: t, t, + do_not_use_native_titlebar, + device_pixel_ratio_override, + } + } + + /// Initialize Application once event loop start running. + pub fn init(&mut self, event_loop: Option<&ActiveEventLoop>) { + // Create rendering context + let rendering_context = if opts::get().headless { + let connection = Connection::new().expect("Failed to create connection"); + let adapter = connection + .create_software_adapter() + .expect("Failed to create adapter"); + RenderingContext::create( + &connection, + &adapter, + Some(opts::get().initial_window_size.to_untyped().to_i32()), + ) + .expect("Failed to create WR surfman") + } else { + let display_handle = event_loop + .unwrap() + .display_handle() + .expect("could not get display handle from window"); + let connection = Connection::from_display_handle(display_handle) + .expect("Failed to create connection"); + let adapter = connection + .create_adapter() + .expect("Failed to create adapter"); + RenderingContext::create(&connection, &adapter, None) + .expect("Failed to create WR surfman") }; - if window.winit_window().is_some() { - // Make sure the gl context is made current. - let rendering_context = window.rendering_context(); - let webrender_gl = match rendering_context.connection().gl_api() { - GLApi::GL => unsafe { - gl::GlFns::load_with(|s| rendering_context.get_proc_address(s)) - }, - GLApi::GLES => unsafe { - gl::GlesFns::load_with(|s| rendering_context.get_proc_address(s)) - }, - }; - rendering_context.make_gl_context_current().unwrap(); - debug_assert_eq!(webrender_gl.get_error(), gleam::gl::NO_ERROR); + let window = if opts::get().headless { + headless_window::Window::new( + opts::get().initial_window_size, + self.device_pixel_ratio_override, + ) + } else { + Rc::new(headed_window::Window::new( + &rendering_context, + opts::get().initial_window_size, + event_loop.unwrap(), + self.do_not_use_native_titlebar, + self.device_pixel_ratio_override, + )) + }; - app.minibrowser = Some( - Minibrowser::new( - &rendering_context, - events_loop.as_winit(), - initial_url.clone(), - ) - .into(), - ); + // Create window's context + self.webviews = Some(WebViewManager::new(window.clone())); + if window.winit_window().is_some() { + self.minibrowser = Some(Minibrowser::new( + &rendering_context, + event_loop.unwrap(), + self.initial_url.clone(), + )); } - if let Some(mut minibrowser) = app.minibrowser() { + if let Some(ref mut minibrowser) = self.minibrowser { // Servo is not yet initialised, so there is no `servo_framebuffer_id`. minibrowser.update( window.winit_window().unwrap(), - &mut app.webviews.borrow_mut(), + self.webviews.as_mut().unwrap(), None, "init", ); window.set_toolbar_height(minibrowser.toolbar_height); } - app.windows.insert(window.id(), window); + self.windows.insert(window.id(), window); - app - } - - /// Initialize Application once event loop start running. - pub fn init(&mut self) { self.suspended.set(false); - self.event_queue.borrow_mut().push(EmbedderEvent::Idle); + self.event_queue.push(EmbedderEvent::Idle); let (_, window) = self.windows.iter().next().unwrap(); - let surfman = window.rendering_context(); let openxr_discovery = if pref!(dom.webxr.openxr.enabled) && !opts::get().headless { #[cfg(target_os = "windows")] @@ -162,9 +193,9 @@ impl App { .expect("An event loop should always be active in headed mode") }); Some(XrDiscovery::GlWindow(GlWindowDiscovery::new( - surfman.connection(), - surfman.adapter(), - surfman.context_attributes(), + rendering_context.connection(), + rendering_context.adapter(), + rendering_context.context_attributes(), factory, ))) } else { @@ -182,17 +213,17 @@ impl App { } else { CompositeTarget::Window }; - let servo_data = Servo::new( + let mut servo = Servo::new( + rendering_context, embedder, window.clone(), self.user_agent.clone(), composite_target, ); - let mut servo = servo_data.servo; servo.handle_events(vec![EmbedderEvent::NewWebView( self.initial_url.to_owned(), - servo_data.browser_id, + WebViewId::new(), )]); servo.setup_logging(); @@ -203,8 +234,8 @@ impl App { self.windows.iter().any(|(_, window)| window.is_animating()) } - fn get_events(&self) -> Vec { - std::mem::take(&mut *self.event_queue.borrow_mut()) + fn get_events(&mut self) -> Vec { + std::mem::take(&mut self.event_queue) } /// Pumps events and messages between the embedder and Servo, where embedder events flow @@ -215,10 +246,10 @@ impl App { /// receive and collect embedder messages from the various Servo components, then take them out /// of the Servo interface so that the WebViewManager can handle them. fn handle_events(&mut self) -> PumpResult { - let mut webviews = self.webviews.borrow_mut(); + let mut embedder_events = self.get_events(); + let webviews = self.webviews.as_mut().unwrap(); // Take any outstanding embedder events from the App and its Windows. - let mut embedder_events = self.get_events(); for window in self.windows.values() { embedder_events.extend(window.get_events()); } @@ -285,21 +316,15 @@ impl App { match self.handle_events() { PumpResult::Shutdown => { event_loop.exit(); - if let Err(e) = window - .rendering_context() - .unbind_native_surface_from_context() - { - error!("Failed to unbind native surface: {e:?}"); - } self.servo.take().unwrap().deinit(); - if let Some(mut minibrowser) = self.minibrowser() { + if let Some(ref mut minibrowser) = self.minibrowser { minibrowser.context.destroy(); } }, PumpResult::Continue { update, present } => { if update { - if let Some(mut minibrowser) = self.minibrowser() { - let webviews = &mut self.webviews.borrow_mut(); + if let Some(ref mut minibrowser) = self.minibrowser { + let webviews = self.webviews.as_mut().unwrap(); if minibrowser.update_webview_data(webviews) { // Update the minibrowser immediately. While we could update by requesting a // redraw, doing so would delay the location update by two frames. @@ -320,10 +345,10 @@ impl App { // If we had resized any of the viewports in response to this, we would need to // call Servo::repaint_synchronously. At the moment we don’t, so there won’t be // any paint scheduled, and calling it would hang the compositor forever. - if let Some(mut minibrowser) = self.minibrowser() { + if let Some(ref mut minibrowser) = self.minibrowser { minibrowser.update( window.winit_window().unwrap(), - &mut self.webviews.borrow_mut(), + self.webviews.as_mut().unwrap(), self.servo.as_ref().unwrap().offscreen_framebuffer_id(), "PumpResult::Present::Immediate", ); @@ -364,14 +389,14 @@ impl App { if self.servo.is_none() { return false; } - self.event_queue.borrow_mut().push(EmbedderEvent::Idle); + self.event_queue.push(EmbedderEvent::Idle); let mut exit = false; match self.handle_events() { PumpResult::Shutdown => { exit = true; self.servo.take().unwrap().deinit(); - if let Some(mut minibrowser) = self.minibrowser() { + if let Some(ref mut minibrowser) = self.minibrowser { minibrowser.context.destroy(); } }, @@ -394,16 +419,12 @@ impl App { } exit } - - fn minibrowser(&self) -> Option> { - self.minibrowser.as_ref().map(|x| x.borrow_mut()) - } } impl ApplicationHandler for App { fn resumed(&mut self, event_loop: &ActiveEventLoop) { let _guard = EventLoopGuard::new(event_loop); - self.init(); + self.init(Some(event_loop)); } fn window_event( @@ -437,10 +458,10 @@ impl ApplicationHandler for App { // WARNING: do not defer painting or presenting to some later tick of the event // loop or servoshell may become unresponsive! (servo#30312) - if let Some(mut minibrowser) = self.minibrowser() { + if let Some(ref mut minibrowser) = self.minibrowser { minibrowser.update( window.winit_window().unwrap(), - &mut self.webviews.borrow_mut(), + self.webviews.as_mut().unwrap(), self.servo.as_ref().unwrap().offscreen_framebuffer_id(), "RedrawRequested", ); @@ -452,7 +473,7 @@ impl ApplicationHandler for App { // Handle the event let mut consumed = false; - if let Some(mut minibrowser) = self.minibrowser() { + if let Some(ref mut minibrowser) = self.minibrowser { match event { WindowEvent::ScaleFactorChanged { scale_factor, .. } => { // Intercept any ScaleFactorChanged events away from EguiGlow::on_window_event, so @@ -482,7 +503,7 @@ impl ApplicationHandler for App { if let WindowEvent::Resized(_) = event { minibrowser.update( window.winit_window().unwrap(), - &mut self.webviews.borrow_mut(), + self.webviews.as_mut().unwrap(), self.servo.as_ref().unwrap().offscreen_framebuffer_id(), "Sync WebView size with Window Resize event", ); @@ -501,7 +522,7 @@ impl ApplicationHandler for App { } if !consumed { if event == winit::event::WindowEvent::RedrawRequested { - self.event_queue.borrow_mut().push(EmbedderEvent::Idle); + self.event_queue.push(EmbedderEvent::Idle); } window.queue_embedder_events_for_winit_event(event); @@ -517,9 +538,9 @@ impl ApplicationHandler for App { } // Consume and handle any events from the Minibrowser. - if let Some(minibrowser) = self.minibrowser() { - let webviews = &mut self.webviews.borrow_mut(); - let app_event_queue = &mut self.event_queue.borrow_mut(); + if let Some(ref minibrowser) = self.minibrowser { + let webviews = &mut self.webviews.as_mut().unwrap(); + let app_event_queue = &mut self.event_queue; minibrowser.queue_embedder_events_for_minibrowser_events(webviews, app_event_queue); } @@ -541,7 +562,7 @@ impl ApplicationHandler for App { if self.servo.is_none() { return; } - self.event_queue.borrow_mut().push(EmbedderEvent::Idle); + self.event_queue.push(EmbedderEvent::Idle); let Some(window) = self.windows.values().next() else { return; @@ -558,9 +579,9 @@ impl ApplicationHandler for App { } // Consume and handle any events from the Minibrowser. - if let Some(minibrowser) = self.minibrowser() { - let webviews = &mut self.webviews.borrow_mut(); - let app_event_queue = &mut self.event_queue.borrow_mut(); + if let Some(ref minibrowser) = self.minibrowser { + let webviews = &mut self.webviews.as_mut().unwrap(); + let app_event_queue = &mut self.event_queue; minibrowser.queue_embedder_events_for_minibrowser_events(webviews, app_event_queue); } diff --git a/ports/servoshell/desktop/cli.rs b/ports/servoshell/desktop/cli.rs index a0364b85a5d..3110fdaba60 100644 --- a/ports/servoshell/desktop/cli.rs +++ b/ports/servoshell/desktop/cli.rs @@ -2,18 +2,15 @@ * 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::rc::Rc; use std::{env, panic, process}; use getopts::Options; -use log::{error, warn}; +use log::error; use servo::config::opts::{self, ArgumentParsingResult}; -use servo::config::set_pref; use servo::servo_config::pref; use crate::desktop::app::App; use crate::desktop::events_loop::EventsLoop; -use crate::desktop::{headed_window, headless_window}; use crate::panic_hook; pub fn main() { @@ -106,29 +103,12 @@ pub fn main() { let event_loop = EventsLoop::new(opts::get().headless, opts::get().output_file.is_some()) .expect("Failed to create events loop"); - // Implements window methods, used by compositor. - // FIXME: We keep the window until application exits. Otherwise, it will cause - // simthay-clipboard thread segfault on Wayland. - let window = if opts::get().headless { - if pref!(media.glvideo.enabled) { - warn!("GL video rendering is not supported on headless windows."); - set_pref!(media.glvideo.enabled, false); - } - headless_window::Window::new(opts::get().initial_window_size, device_pixel_ratio_override) - } else { - Rc::new(headed_window::Window::new( - opts::get().initial_window_size, - event_loop.as_winit(), - do_not_use_native_titlebar, - device_pixel_ratio_override, - )) - }; - let mut app = App::new( &event_loop, - window.clone(), user_agent, url_opt.map(|s| s.to_string()), + do_not_use_native_titlebar, + device_pixel_ratio_override, ); event_loop.run_app(&mut app); diff --git a/ports/servoshell/desktop/egui_glue.rs b/ports/servoshell/desktop/egui_glue.rs index 48bc39466f0..6cc43ca3a66 100644 --- a/ports/servoshell/desktop/egui_glue.rs +++ b/ports/servoshell/desktop/egui_glue.rs @@ -38,6 +38,7 @@ use egui_glow::ShaderVersion; pub use egui_winit; use egui_winit::winit; pub use egui_winit::EventResponse; +use winit::event_loop::ActiveEventLoop; /// Use [`egui`] from a [`glow`] app based on [`winit`]. pub struct EguiGlow { @@ -52,7 +53,7 @@ pub struct EguiGlow { impl EguiGlow { /// For automatic shader version detection set `shader_version` to `None`. pub fn new( - event_loop: &winit::event_loop::EventLoop, + event_loop: &ActiveEventLoop, gl: std::sync::Arc, shader_version: Option, ) -> Self { diff --git a/ports/servoshell/desktop/events_loop.rs b/ports/servoshell/desktop/events_loop.rs index c598dd5f2b3..118de1ae99c 100644 --- a/ports/servoshell/desktop/events_loop.rs +++ b/ports/servoshell/desktop/events_loop.rs @@ -9,6 +9,7 @@ use std::sync::{Arc, Condvar, Mutex}; use std::time; use log::warn; +use servo::config::{pref, set_pref}; use servo::embedder_traits::EventLoopWaker; use winit::error::EventLoopError; use winit::event_loop::{ActiveEventLoop, EventLoop as WinitEventLoop}; @@ -79,14 +80,7 @@ impl EventsLoop { EventLoop::Headless(ref data) => Box::new(HeadlessEventLoopWaker(data.clone())), } } - pub fn as_winit(&self) -> &WinitEventLoop { - match self.0 { - EventLoop::Winit(Some(ref event_loop)) => event_loop, - EventLoop::Winit(None) | EventLoop::Headless(..) => { - panic!("Can't access winit event loop while using the fake headless event loop") - }, - } - } + pub fn run_app(self, app: &mut App) { match self.0 { EventLoop::Winit(events_loop) => { @@ -97,7 +91,12 @@ impl EventsLoop { }, EventLoop::Headless(ref data) => { let (flag, condvar) = &**data; - app.init(); + if pref!(media.glvideo.enabled) { + warn!("GL video rendering is not supported on headless windows."); + set_pref!(media.glvideo.enabled, false); + } + + app.init(None); loop { self.sleep(flag, condvar); if app.handle_events_with_headless() { diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index d80908361b8..11b95191655 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -10,7 +10,7 @@ use std::rc::Rc; use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D}; use log::{debug, info, trace}; -use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +use raw_window_handle::HasWindowHandle; use servo::compositing::windowing::{ AnimationState, EmbedderCoordinates, EmbedderEvent, MouseWindowEvent, WindowMethods, }; @@ -22,21 +22,20 @@ use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel}; use servo::webrender_api::ScrollLocation; use servo::webrender_traits::RenderingContext; -use surfman::{Connection, Context, Device, SurfaceType}; +use surfman::{Context, Device, SurfaceType}; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; use winit::event::{ElementState, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase}; +use winit::event_loop::ActiveEventLoop; use winit::keyboard::{Key as LogicalKey, ModifiersState, NamedKey}; #[cfg(any(target_os = "linux", target_os = "windows"))] use winit::window::Icon; -use super::events_loop::WakerEvent; use super::geometry::{winit_position_to_euclid_point, winit_size_to_euclid_size}; use super::keyutils::keyboard_event_from_winit; use super::window_trait::{WindowPortsMethods, LINE_HEIGHT}; pub struct Window { winit_window: winit::window::Window, - rendering_context: RenderingContext, screen_size: Size2D, inner_size: Cell>, toolbar_height: Cell>, @@ -58,8 +57,9 @@ pub struct Window { impl Window { pub fn new( + rendering_context: &RenderingContext, window_size: Size2D, - event_loop: &winit::event_loop::EventLoop, + event_loop: &ActiveEventLoop, no_native_titlebar: bool, device_pixel_ratio_override: Option, ) -> Window { @@ -103,20 +103,13 @@ impl Window { let screen_size = (winit_size_to_euclid_size(screen_size).to_f64() / screen_scale).to_u32(); // Initialize surfman - let display_handle = winit_window - .display_handle() - .expect("could not get display handle from window"); - let connection = - Connection::from_display_handle(display_handle).expect("Failed to create connection"); - let adapter = connection - .create_adapter() - .expect("Failed to create adapter"); let window_handle = winit_window .window_handle() .expect("could not get window handle from window"); let inner_size = winit_window.inner_size(); - let native_widget = connection + let native_widget = rendering_context + .connection() .create_native_widget_from_window_handle( window_handle, winit_size_to_euclid_size(inner_size).to_i32().to_untyped(), @@ -124,13 +117,18 @@ impl Window { .expect("Failed to create native widget"); let surface_type = SurfaceType::Widget { native_widget }; - let rendering_context = RenderingContext::create(&connection, &adapter, surface_type) - .expect("Failed to create WR surfman"); + let surface = rendering_context + .create_surface(surface_type) + .expect("Failed to create surface"); + rendering_context + .bind_surface(surface) + .expect("Failed to bind surface"); + // Make sure the gl context is made current. + rendering_context.make_gl_context_current().unwrap(); debug!("Created window {:?}", winit_window.id()); Window { winit_window, - rendering_context, event_queue: RefCell::new(vec![]), mouse_down_button: Cell::new(None), mouse_down_point: Cell::new(Point2D::zero()), @@ -478,9 +476,6 @@ impl WindowPortsMethods for Window { }, winit::event::WindowEvent::Resized(new_size) => { if self.inner_size.get() != new_size { - self.rendering_context - .resize(Size2D::new(new_size.width, new_size.height).to_i32()) - .expect("Failed to resize"); self.inner_size.set(new_size); self.event_queue .borrow_mut() @@ -565,10 +560,6 @@ impl WindowMethods for Window { fn set_animation_state(&self, state: AnimationState) { self.animation_state.set(state); } - - fn rendering_context(&self) -> RenderingContext { - self.rendering_context.clone() - } } fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { diff --git a/ports/servoshell/desktop/headless_window.rs b/ports/servoshell/desktop/headless_window.rs index d15f4b3680e..fc4412197b6 100644 --- a/ports/servoshell/desktop/headless_window.rs +++ b/ports/servoshell/desktop/headless_window.rs @@ -10,20 +10,17 @@ use std::sync::RwLock; use euclid::num::Zero; use euclid::{Box2D, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D}; -use log::warn; use servo::compositing::windowing::{ AnimationState, EmbedderCoordinates, EmbedderEvent, WindowMethods, }; use servo::config::opts; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::units::{DeviceIntSize, DevicePixel}; -use servo::webrender_traits::RenderingContext; -use surfman::{Connection, Context, Device, SurfaceType}; +use surfman::{Context, Device}; use crate::desktop::window_trait::WindowPortsMethods; pub struct Window { - rendering_context: RenderingContext, animation_state: Cell, fullscreen: Cell, device_pixel_ratio_override: Option>, @@ -39,17 +36,6 @@ impl Window { size: Size2D, device_pixel_ratio_override: Option, ) -> Rc { - // Initialize surfman - let connection = Connection::new().expect("Failed to create connection"); - let adapter = connection - .create_software_adapter() - .expect("Failed to create adapter"); - let surface_type = SurfaceType::Generic { - size: size.to_untyped().to_i32(), - }; - let rendering_context = RenderingContext::create(&connection, &adapter, surface_type) - .expect("Failed to create WR surfman"); - let device_pixel_ratio_override: Option> = device_pixel_ratio_override.map(Scale::new); let hidpi_factor = device_pixel_ratio_override.unwrap_or_else(Scale::identity); @@ -64,7 +50,6 @@ impl Window { ); let window = Window { - rendering_context, animation_state: Cell::new(AnimationState::Idle), fullscreen: Cell::new(false), device_pixel_ratio_override, @@ -97,19 +82,11 @@ impl WindowPortsMethods for Window { return Some(new_size); } - match self.rendering_context.resize(new_size.to_untyped()) { - Ok(()) => { - self.inner_size.set(new_size); - if let Ok(ref mut queue) = self.event_queue.write() { - queue.push(EmbedderEvent::WindowResize); - } - Some(new_size) - }, - Err(error) => { - warn!("Could not resize window: {error:?}"); - None - }, + self.inner_size.set(new_size); + if let Ok(ref mut queue) = self.event_queue.write() { + queue.push(EmbedderEvent::WindowResize); } + Some(new_size) } fn device_hidpi_factor(&self) -> Scale { @@ -123,12 +100,7 @@ impl WindowPortsMethods for Window { } fn page_height(&self) -> f32 { - let height = self - .rendering_context - .context_surface_info() - .unwrap_or(None) - .map(|info| info.size.height) - .unwrap_or(0); + let height = self.inner_size.get().height; let dpr = self.hidpi_factor(); height as f32 * dpr.get() } @@ -185,10 +157,6 @@ impl WindowMethods for Window { fn set_animation_state(&self, state: AnimationState) { self.animation_state.set(state); } - - fn rendering_context(&self) -> RenderingContext { - self.rendering_context.clone() - } } impl webxr::glwindow::GlWindow for Window { diff --git a/ports/servoshell/desktop/minibrowser.rs b/ports/servoshell/desktop/minibrowser.rs index 22f06f82879..51bfbb76ecc 100644 --- a/ports/servoshell/desktop/minibrowser.rs +++ b/ports/servoshell/desktop/minibrowser.rs @@ -28,11 +28,10 @@ use servo::webrender_api::units::DevicePixel; use servo::webrender_traits::RenderingContext; use servo::TopLevelBrowsingContextId; use winit::event::{ElementState, MouseButton, WindowEvent}; -use winit::event_loop::EventLoop; +use winit::event_loop::ActiveEventLoop; use winit::window::Window; use super::egui_glue::EguiGlow; -use super::events_loop::WakerEvent; use super::geometry::winit_position_to_euclid_point; use super::webview::{LoadStatus, WebViewManager}; use super::window_trait::WindowPortsMethods; @@ -80,7 +79,7 @@ fn truncate_with_ellipsis(input: &str, max_length: usize) -> String { impl Minibrowser { pub fn new( rendering_context: &RenderingContext, - event_loop: &EventLoop, + event_loop: &ActiveEventLoop, initial_url: ServoUrl, ) -> Self { let gl = unsafe { diff --git a/ports/servoshell/egl/android/simpleservo.rs b/ports/servoshell/egl/android/simpleservo.rs index 1c110ad9a20..b90530ec732 100644 --- a/ports/servoshell/egl/android/simpleservo.rs +++ b/ports/servoshell/egl/android/simpleservo.rs @@ -9,6 +9,7 @@ use std::os::raw::c_void; use std::rc::Rc; use getopts::Options; +use servo::base::id::WebViewId; use servo::compositing::windowing::EmbedderEvent; use servo::compositing::CompositeTarget; pub use servo::config::prefs::{add_user_prefs, PrefValue}; @@ -93,14 +94,19 @@ pub fn init( SurfaceType::Widget { native_widget } }, }; - let rendering_context = RenderingContext::create(&connection, &adapter, surface_type) + let rendering_context = RenderingContext::create(&connection, &adapter, None) .or(Err("Failed to create surface manager"))?; + let surface = rendering_context + .create_surface(surface_type) + .or(Err("Failed to create surface"))?; + rendering_context + .bind_surface(surface) + .or(Err("Failed to bind surface"))?; let window_callbacks = Rc::new(ServoWindowCallbacks::new( callbacks, RefCell::new(init_opts.coordinates), init_opts.density, - rendering_context.clone(), )); let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( @@ -110,6 +116,7 @@ pub fn init( )); let servo = Servo::new( + rendering_context.clone(), embedder_callbacks, window_callbacks.clone(), None, @@ -117,8 +124,8 @@ pub fn init( ); SERVO.with(|s| { - let mut servo_glue = ServoGlue::new(rendering_context, servo.servo, window_callbacks, None); - let _ = servo_glue.process_event(EmbedderEvent::NewWebView(url, servo.browser_id)); + let mut servo_glue = ServoGlue::new(rendering_context, servo, window_callbacks, None); + let _ = servo_glue.process_event(EmbedderEvent::NewWebView(url, WebViewId::new())); *s.borrow_mut() = Some(servo_glue); }); diff --git a/ports/servoshell/egl/ohos/simpleservo.rs b/ports/servoshell/egl/ohos/simpleservo.rs index 97e0e02f072..8aff4d41a26 100644 --- a/ports/servoshell/egl/ohos/simpleservo.rs +++ b/ports/servoshell/egl/ohos/simpleservo.rs @@ -9,6 +9,7 @@ use std::rc::Rc; use log::{debug, error, info}; use ohos_sys::xcomponent::{OH_NativeXComponent, OH_NativeXComponent_GetXComponentSize}; +use servo::base::id::WebViewId; use servo::compositing::windowing::EmbedderEvent; use servo::compositing::CompositeTarget; use servo::embedder_traits::resources; @@ -118,8 +119,14 @@ pub fn init( let surface_type = SurfaceType::Widget { native_widget }; info!("Creating rendering context"); - let rendering_context = RenderingContext::create(&connection, &adapter, surface_type) + let rendering_context = RenderingContext::create(&connection, &adapter, None) .or(Err("Failed to create surface manager"))?; + let surface = rendering_context + .create_surface(surface_type) + .or(Err("Failed to create surface"))?; + rendering_context + .bind_surface(surface) + .or(Err("Failed to bind surface"))?; info!("before ServoWindowCallbacks..."); @@ -127,7 +134,6 @@ pub fn init( callbacks, RefCell::new(Coordinates::new(0, 0, width, height, width, height)), options.display_density as f32, - rendering_context.clone(), )); let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( @@ -137,6 +143,7 @@ pub fn init( )); let servo = Servo::new( + rendering_context.clone(), embedder_callbacks, window_callbacks.clone(), // User agent: Mozilla/5.0 (; HarmonyOS 5.0) bla bla @@ -146,7 +153,7 @@ pub fn init( let mut servo_glue = ServoGlue::new( rendering_context, - servo.servo, + servo, window_callbacks, Some(options.resource_dir), ); @@ -156,7 +163,7 @@ pub fn init( .ok() .unwrap_or_else(|| ServoUrl::parse("about:blank").expect("Infallible")); - let _ = servo_glue.process_event(EmbedderEvent::NewWebView(initial_url, servo.browser_id)); + let _ = servo_glue.process_event(EmbedderEvent::NewWebView(initial_url, WebViewId::new())); Ok(servo_glue) } diff --git a/ports/servoshell/egl/servo_glue.rs b/ports/servoshell/egl/servo_glue.rs index 381e72c4dae..042bff8c957 100644 --- a/ports/servoshell/egl/servo_glue.rs +++ b/ports/servoshell/egl/servo_glue.rs @@ -58,7 +58,6 @@ pub(super) struct ServoWindowCallbacks { host_callbacks: Box, coordinates: RefCell, hidpi_factor: Scale, - rendering_context: RenderingContext, } impl ServoWindowCallbacks { @@ -66,13 +65,11 @@ impl ServoWindowCallbacks { host_callbacks: Box, coordinates: RefCell, hidpi_factor: f32, - rendering_context: RenderingContext, ) -> Self { Self { host_callbacks, coordinates, hidpi_factor: Scale::new(hidpi_factor), - rendering_context, } } } @@ -549,6 +546,8 @@ impl ServoGlue { }, EmbedderMsg::WebViewFocused(webview_id) => { self.focused_webview_id = Some(webview_id); + self.events + .push(EmbedderEvent::ShowWebView(webview_id, true)); }, EmbedderMsg::WebViewBlurred => { self.focused_webview_id = None; @@ -717,8 +716,4 @@ impl WindowMethods for ServoWindowCallbacks { self.host_callbacks .on_animating_changed(state == AnimationState::Animating); } - - fn rendering_context(&self) -> RenderingContext { - self.rendering_context.clone() - } }