libservo: Expose SoftwareRenderingContext and WindowRenderingContext (#35501)

Expose two easy-to-use wrappers around `SurfmanRenderingContext` that
make the API simpler to use:

- `WindowRenderingContext`: This `RenderingContext` is a newtype around
  `SurfmanRenderingContext` takes a `raw-window-handle` display and window
  and creates a full window rendering context.
- `SoftwareRenderingContext`: is wraps `SurfmanRenderingContext` and
  adds a swap chain in order to expose a software GL rendering context.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-02-18 15:50:41 +01:00 committed by GitHub
parent 73507f58e6
commit f34f2d9d0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 514 additions and 470 deletions

3
Cargo.lock generated
View file

@ -6876,6 +6876,7 @@ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
"dirs", "dirs",
"dpi",
"egui", "egui",
"egui-file-dialog", "egui-file-dialog",
"egui-winit", "egui-winit",
@ -8592,6 +8593,7 @@ name = "webrender_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"base", "base",
"dpi",
"embedder_traits", "embedder_traits",
"euclid", "euclid",
"gleam", "gleam",
@ -8600,6 +8602,7 @@ dependencies = [
"ipc-channel", "ipc-channel",
"libc", "libc",
"log", "log",
"raw-window-handle",
"serde", "serde",
"servo-media", "servo-media",
"servo_geometry", "servo_geometry",

View file

@ -48,6 +48,7 @@ ctr = "0.9.2"
darling = { version = "0.20", default-features = false } darling = { version = "0.20", default-features = false }
data-url = "0.3" data-url = "0.3"
devtools_traits = { path = "components/shared/devtools" } devtools_traits = { path = "components/shared/devtools" }
dpi = { version = "0.1" }
embedder_traits = { path = "components/shared/embedder" } embedder_traits = { path = "components/shared/embedder" }
encoding_rs = "0.8" encoding_rs = "0.8"
env_logger = "0.10" env_logger = "0.10"

View file

@ -36,7 +36,6 @@ script_traits = { workspace = true }
servo_config = { path = "../config" } servo_config = { path = "../config" }
servo_geometry = { path = "../geometry" } servo_geometry = { path = "../geometry" }
style_traits = { workspace = true } style_traits = { workspace = true }
surfman = { workspace = true }
tracing = { workspace = true, optional = true } tracing = { workspace = true, optional = true }
webrender = { workspace = true } webrender = { workspace = true }
webrender_api = { workspace = true } webrender_api = { workspace = true }

View file

@ -8,14 +8,12 @@ use std::rc::Rc;
use compositing::windowing::{AnimationState, EmbedderMethods, WindowMethods}; use compositing::windowing::{AnimationState, EmbedderMethods, WindowMethods};
use euclid::{Point2D, Scale, Size2D}; use euclid::{Point2D, Scale, Size2D};
use servo::{Servo, TouchEventType, WebView}; use servo::{RenderingContext, Servo, TouchEventAction, WebView, WindowRenderingContext};
use servo_geometry::DeviceIndependentPixel; use servo_geometry::DeviceIndependentPixel;
use surfman::{Connection, SurfaceType};
use tracing::warn; use tracing::warn;
use url::Url; use url::Url;
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DevicePixel, LayoutVector2D}; use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DevicePixel, LayoutVector2D};
use webrender_api::ScrollLocation; use webrender_api::ScrollLocation;
use webrender_traits::SurfmanRenderingContext;
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::event::{MouseScrollDelta, WindowEvent}; use winit::event::{MouseScrollDelta, WindowEvent};
@ -62,7 +60,7 @@ impl ::servo::WebViewDelegate for AppState {
} }
fn notify_new_frame_ready(&self, _: WebView) { fn notify_new_frame_ready(&self, _: WebView) {
self.servo.present(); self.window_delegate.window.request_redraw();
} }
fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option<WebView> { fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option<WebView> {
@ -87,38 +85,21 @@ impl App {
impl ApplicationHandler<WakerEvent> for App { impl ApplicationHandler<WakerEvent> for App {
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
if let Self::Initial(waker) = self { if let Self::Initial(waker) = self {
let window = event_loop
.create_window(Window::default_attributes())
.expect("Failed to create winit Window");
let display_handle = event_loop let display_handle = event_loop
.display_handle() .display_handle()
.expect("Failed to get display handle"); .expect("Failed to get display handle");
let connection = Connection::from_display_handle(display_handle) let window = event_loop
.expect("Failed to create connection"); .create_window(Window::default_attributes())
let adapter = connection .expect("Failed to create winit Window");
.create_adapter() let window_handle = window.window_handle().expect("Failed to get window handle");
.expect("Failed to create adapter");
let rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None) let rendering_context =
.expect("Failed to create rendering context"); WindowRenderingContext::new(display_handle, window_handle, &window.inner_size())
let native_widget = rendering_context .expect("Could not create RenderingContext for window.");
.connection()
.create_native_widget_from_window_handle(
window.window_handle().expect("Failed to get window handle"),
winit_size_to_euclid_size(window.inner_size())
.to_i32()
.to_untyped(),
)
.expect("Failed to create native widget");
let surface = rendering_context
.create_surface(SurfaceType::Widget { native_widget })
.expect("Failed to create surface");
rendering_context
.bind_surface(surface)
.expect("Failed to bind surface");
rendering_context
.make_gl_context_current()
.expect("Failed to make context current");
let window_delegate = Rc::new(WindowDelegate::new(window)); let window_delegate = Rc::new(WindowDelegate::new(window));
let _ = rendering_context.make_current();
let servo = Servo::new( let servo = Servo::new(
Default::default(), Default::default(),
Default::default(), Default::default(),
@ -139,7 +120,8 @@ impl ApplicationHandler<WakerEvent> for App {
}); });
// Make a new WebView and assign the `AppState` as the delegate. // Make a new WebView and assign the `AppState` as the delegate.
let url = Url::parse("https://servo.org").expect("Guaranteed by argument"); let url = Url::parse("https://demo.servo.org/experiments/twgl-tunnel/")
.expect("Guaranteed by argument");
let webview = app_state.servo.new_webview(url); let webview = app_state.servo.new_webview(url);
webview.set_delegate(app_state.clone()); webview.set_delegate(app_state.clone());
app_state.webviews.borrow_mut().push(webview); app_state.webviews.borrow_mut().push(webview);
@ -170,7 +152,7 @@ impl ApplicationHandler<WakerEvent> for App {
}, },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
if let Self::Running(state) = self { if let Self::Running(state) = self {
state.webviews.borrow().last().unwrap().composite(); state.webviews.borrow().last().unwrap().paint_immediately();
state.servo.present(); state.servo.present();
} }
}, },
@ -188,7 +170,7 @@ impl ApplicationHandler<WakerEvent> for App {
webview.notify_scroll_event( webview.notify_scroll_event(
ScrollLocation::Delta(moved_by), ScrollLocation::Delta(moved_by),
DeviceIntPoint::new(10, 10), DeviceIntPoint::new(10, 10),
TouchEventType::Down, TouchEventAction::Down,
); );
} }
} }

View file

@ -101,7 +101,11 @@ pub use webgpu;
use webgpu::swapchain::WGPUImageMap; use webgpu::swapchain::WGPUImageMap;
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT}; use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
use webrender_api::{ColorF, DocumentId, FramePublishId}; use webrender_api::{ColorF, DocumentId, FramePublishId};
use webrender_traits::rendering_context::{GLVersion, RenderingContext}; use webrender_traits::rendering_context::GLVersion;
pub use webrender_traits::rendering_context::{
OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, SurfmanRenderingContext,
WindowRenderingContext,
};
use webrender_traits::{ use webrender_traits::{
CrossProcessCompositorApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, CrossProcessCompositorApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry,
WebrenderImageHandlerType, WebrenderImageHandlerType,
@ -113,7 +117,7 @@ pub use {
background_hang_monitor, base, canvas, canvas_traits, compositing, devtools, devtools_traits, background_hang_monitor, base, canvas, canvas_traits, compositing, devtools, devtools_traits,
euclid, fonts, ipc_channel, layout_thread_2020, media, net, net_traits, profile, euclid, fonts, ipc_channel, layout_thread_2020, media, net, net_traits, profile,
profile_traits, script, script_layout_interface, script_traits, servo_config as config, profile_traits, script, script_layout_interface, script_traits, servo_config as config,
servo_config, servo_geometry, servo_url, style, style_traits, webrender_api, webrender_traits, servo_config, servo_geometry, servo_url, style, style_traits, webrender_api,
}; };
#[cfg(feature = "bluetooth")] #[cfg(feature = "bluetooth")]
pub use {bluetooth, bluetooth_traits}; pub use {bluetooth, bluetooth_traits};

View file

@ -414,4 +414,8 @@ impl WebView {
.constellation_proxy .constellation_proxy
.send(ConstellationMsg::SendError(Some(self.id()), message)); .send(ConstellationMsg::SendError(Some(self.id()), message));
} }
pub fn paint_immediately(&self) {
self.inner().compositor.borrow_mut().composite();
}
} }

View file

@ -31,3 +31,5 @@ servo_geometry = { path = "../../geometry" }
servo-media = { workspace = true } servo-media = { workspace = true }
style = { workspace = true } style = { workspace = true }
surfman = { workspace = true, features = ["sm-x11"] } surfman = { workspace = true, features = ["sm-x11"] }
raw-window-handle = { version = "0.6" }
dpi = { version = "0.1" }

View file

@ -28,8 +28,6 @@ use webrender_api::{
ImageKey, NativeFontHandle, PipelineId as WebRenderPipelineId, ImageKey, NativeFontHandle, PipelineId as WebRenderPipelineId,
}; };
pub use crate::rendering_context::SurfmanRenderingContext;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub enum CrossProcessCompositorMessage { pub enum CrossProcessCompositorMessage {
/// Inform WebRender of the existence of this pipeline. /// Inform WebRender of the existence of this pipeline.

View file

@ -9,12 +9,14 @@ use std::ffi::c_void;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::rc::Rc; use std::rc::Rc;
use dpi::PhysicalSize;
use euclid::default::{Rect, Size2D}; use euclid::default::{Rect, Size2D};
use euclid::Point2D; use euclid::Point2D;
use gleam::gl::{self, Gl}; use gleam::gl::{self, Gl};
use glow::NativeFramebuffer; use glow::NativeFramebuffer;
use image::RgbaImage; use image::RgbaImage;
use log::{debug, trace, warn}; use log::{debug, trace, warn};
use raw_window_handle::{DisplayHandle, WindowHandle};
use servo_media::player::context::{GlContext, NativeDisplay}; use servo_media::player::context::{GlContext, NativeDisplay};
use surfman::chains::{PreserveBuffer, SwapChain}; use surfman::chains::{PreserveBuffer, SwapChain};
#[cfg(all(target_os = "linux", not(target_env = "ohos")))] #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
@ -24,8 +26,7 @@ use surfman::platform::generic::multi::context::NativeContext as LinuxNativeCont
pub use surfman::Error; pub use surfman::Error;
use surfman::{ use surfman::{
Adapter, Connection, Context, ContextAttributeFlags, ContextAttributes, Device, GLApi, Adapter, Connection, Context, ContextAttributeFlags, ContextAttributes, Device, GLApi,
NativeContext, NativeDevice, NativeWidget, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, NativeContext, NativeWidget, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, SurfaceType,
SurfaceType,
}; };
/// Describes the OpenGL version that is requested when a context is created. /// Describes the OpenGL version that is requested when a context is created.
@ -81,7 +82,6 @@ pub trait RenderingContext {
fn destroy_texture(&self, _surface_texture: SurfaceTexture) -> Option<Surface> { fn destroy_texture(&self, _surface_texture: SurfaceTexture) -> Option<Surface> {
None None
} }
/// The connection to the display server for WebGL. Default to `None`. /// The connection to the display server for WebGL. Default to `None`.
fn connection(&self) -> Option<Connection> { fn connection(&self) -> Option<Connection> {
None None
@ -96,28 +96,124 @@ pub trait RenderingContext {
/// The `SurfmanRenderingContext` struct encapsulates the necessary data and methods /// The `SurfmanRenderingContext` struct encapsulates the necessary data and methods
/// to interact with the Surfman library, including creating surfaces, binding surfaces, /// to interact with the Surfman library, including creating surfaces, binding surfaces,
/// resizing surfaces, presenting rendered frames, and managing the OpenGL context state. /// resizing surfaces, presenting rendered frames, and managing the OpenGL context state.
#[derive(Clone)] pub struct SurfmanRenderingContext {
pub struct SurfmanRenderingContext(Rc<RenderingContextData>);
struct RenderingContextData {
gl: Rc<dyn Gl>, gl: Rc<dyn Gl>,
device: RefCell<Device>, device: RefCell<Device>,
context: RefCell<Context>, context: RefCell<Context>,
// We either render to a swap buffer or to a native widget
swap_chain: Option<SwapChain<Device>>,
} }
impl Drop for RenderingContextData { impl Drop for SurfmanRenderingContext {
fn drop(&mut self) { fn drop(&mut self) {
let device = &mut self.device.borrow_mut(); let device = &mut self.device.borrow_mut();
let context = &mut self.context.borrow_mut(); let context = &mut self.context.borrow_mut();
if let Some(ref swap_chain) = self.swap_chain {
let _ = swap_chain.destroy(device, context);
}
let _ = device.destroy_context(context); let _ = device.destroy_context(context);
} }
} }
impl SurfmanRenderingContext {
fn new(connection: &Connection, adapter: &Adapter) -> Result<Self, Error> {
let mut device = connection.create_device(adapter)?;
let flags = ContextAttributeFlags::ALPHA |
ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL;
let gl_api = connection.gl_api();
let version = match &gl_api {
GLApi::GLES => surfman::GLVersion { major: 3, minor: 0 },
GLApi::GL => surfman::GLVersion { major: 3, minor: 2 },
};
let context_descriptor =
device.create_context_descriptor(&ContextAttributes { flags, version })?;
let context = device.create_context(&context_descriptor, None)?;
#[allow(unsafe_code)]
let gl = {
match gl_api {
GLApi::GL => unsafe {
gl::GlFns::load_with(|func_name| device.get_proc_address(&context, func_name))
},
GLApi::GLES => unsafe {
gl::GlesFns::load_with(|func_name| device.get_proc_address(&context, func_name))
},
}
};
Ok(SurfmanRenderingContext {
gl,
device: RefCell::new(device),
context: RefCell::new(context),
})
}
fn create_surface(&self, surface_type: SurfaceType<NativeWidget>) -> Result<Surface, Error> {
let device = &mut self.device.borrow_mut();
let context = &self.context.borrow();
device.create_surface(context, SurfaceAccess::GPUOnly, surface_type)
}
fn bind_surface(&self, surface: Surface) -> Result<(), Error> {
let device = &self.device.borrow();
let context = &mut self.context.borrow_mut();
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})?;
Ok(())
}
fn create_attached_swap_chain(&self) -> Result<SwapChain<Device>, Error> {
let device = &mut self.device.borrow_mut();
let context = &mut self.context.borrow_mut();
SwapChain::create_attached(device, context, SurfaceAccess::GPUOnly)
}
fn resize_surface(&self, size: Size2D<i32>) -> Result<(), Error> {
let device = &mut self.device.borrow_mut();
let context = &mut self.context.borrow_mut();
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.resize_surface(context, &mut surface, size)?;
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})
}
fn present_bound_surface(&self) -> Result<(), Error> {
let device = &self.device.borrow();
let context = &mut self.context.borrow_mut();
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.present_surface(context, &mut surface)?;
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})
}
#[allow(dead_code)]
fn native_context(&self) -> NativeContext {
let device = &self.device.borrow();
let context = &self.context.borrow();
device.native_context(context)
}
fn framebuffer(&self) -> Option<NativeFramebuffer> {
let device = &self.device.borrow();
let context = &self.context.borrow();
device
.context_surface_info(context)
.unwrap_or(None)
.and_then(|info| info.framebuffer_object)
}
}
impl RenderingContext for SurfmanRenderingContext { impl RenderingContext for SurfmanRenderingContext {
fn gl_context(&self) -> GlContext { fn gl_context(&self) -> GlContext {
#[cfg(all(target_os = "linux", not(target_env = "ohos")))] #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
@ -149,10 +245,11 @@ impl RenderingContext for SurfmanRenderingContext {
GlContext::Unknown GlContext::Unknown
} }
} }
fn gl_display(&self) -> NativeDisplay { fn gl_display(&self) -> NativeDisplay {
#[cfg(all(target_os = "linux", not(target_env = "ohos")))] #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
{ {
match self.connection().native_connection() { match self.device.borrow().connection().native_connection() {
surfman::NativeConnection::Default(LinuxNativeConnection::Default(connection)) => { surfman::NativeConnection::Default(LinuxNativeConnection::Default(connection)) => {
NativeDisplay::Egl(connection.0 as usize) NativeDisplay::Egl(connection.0 as usize)
}, },
@ -166,7 +263,8 @@ impl RenderingContext for SurfmanRenderingContext {
{ {
#[cfg(feature = "no-wgl")] #[cfg(feature = "no-wgl")]
{ {
NativeDisplay::Egl(self.native_device().egl_display as usize) let device = &self.device.borrow();
NativeDisplay::Egl(device.native_device().egl_display as usize)
} }
#[cfg(not(feature = "no-wgl"))] #[cfg(not(feature = "no-wgl"))]
NativeDisplay::Unknown NativeDisplay::Unknown
@ -180,55 +278,59 @@ impl RenderingContext for SurfmanRenderingContext {
} }
} }
fn prepare_for_rendering(&self) {
self.0.gl.bind_framebuffer(
gleam::gl::FRAMEBUFFER,
self.framebuffer()
.map_or(0, |framebuffer| framebuffer.0.into()),
);
}
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
let framebuffer_id = self
.framebuffer()
.map(|framebuffer| framebuffer.0.into())
.unwrap_or(0);
Framebuffer::read_framebuffer_to_image(self.gl_api(), framebuffer_id, source_rectangle)
}
fn resize(&self, size: Size2D<i32>) {
if let Err(err) = self.resize(size) {
warn!("Failed to resize surface: {:?}", err);
}
}
fn present(&self) {
if let Err(err) = self.present() {
warn!("Failed to present surface: {:?}", err);
}
}
fn make_current(&self) -> Result<(), Error> {
self.make_gl_context_current()
}
#[allow(unsafe_code)]
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
self.0.gl.clone()
}
fn gl_version(&self) -> GLVersion { fn gl_version(&self) -> GLVersion {
let device = self.0.device.borrow(); let device = self.device.borrow();
let context = self.0.context.borrow(); let context = self.context.borrow();
let descriptor = device.context_descriptor(&context); let descriptor = device.context_descriptor(&context);
let attributes = device.context_descriptor_attributes(&descriptor); let attributes = device.context_descriptor_attributes(&descriptor);
let major = attributes.version.major; let major = attributes.version.major;
let minor = attributes.version.minor; let minor = attributes.version.minor;
match self.connection().gl_api() { match device.connection().gl_api() {
GLApi::GL => GLVersion::GL(major, minor), GLApi::GL => GLVersion::GL(major, minor),
GLApi::GLES => GLVersion::GLES(major, minor), GLApi::GLES => GLVersion::GLES(major, minor),
} }
} }
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
self.gl.clone()
}
fn prepare_for_rendering(&self) {
let framebuffer_id = self
.framebuffer()
.map_or(0, |framebuffer| framebuffer.0.into());
self.gl
.bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_id);
}
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
let framebuffer_id = self
.framebuffer()
.map_or(0, |framebuffer| framebuffer.0.into());
Framebuffer::read_framebuffer_to_image(&self.gl, framebuffer_id, source_rectangle)
}
fn resize(&self, size: Size2D<i32>) {
if let Err(error) = self.resize_surface(size) {
warn!("Error resizing surface: {error:?}");
}
}
fn present(&self) {
if let Err(error) = self.present_bound_surface() {
warn!("Error presenting surface: {error:?}");
}
}
fn make_current(&self) -> Result<(), Error> {
let device = &self.device.borrow();
let context = &mut self.context.borrow();
device.make_context_current(context)
}
fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> { fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {
let device = &self.0.device.borrow(); let device = &self.device.borrow();
let context = &mut self.0.context.borrow_mut(); let context = &mut self.context.borrow_mut();
let SurfaceInfo { let SurfaceInfo {
id: front_buffer_id, id: front_buffer_id,
size, size,
@ -244,236 +346,164 @@ impl RenderingContext for SurfmanRenderingContext {
} }
fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> { fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {
self.destroy_surface_texture(surface_texture).ok() let device = &self.device.borrow();
} let context = &mut self.context.borrow_mut();
fn connection(&self) -> Option<Connection> {
Some(self.connection())
}
}
impl SurfmanRenderingContext {
pub fn create(
connection: &Connection,
adapter: &Adapter,
headless: Option<Size2D<i32>>,
) -> Result<Self, Error> {
let mut device = connection.create_device(adapter)?;
let flags = ContextAttributeFlags::ALPHA |
ContextAttributeFlags::DEPTH |
ContextAttributeFlags::STENCIL;
let version = match connection.gl_api() {
GLApi::GLES => surfman::GLVersion { major: 3, minor: 0 },
GLApi::GL => surfman::GLVersion { major: 3, minor: 2 },
};
let context_attributes = ContextAttributes { flags, version };
let context_descriptor = device.create_context_descriptor(&context_attributes)?;
let mut context = device.create_context(&context_descriptor, None)?;
let surface_access = SurfaceAccess::GPUOnly;
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,
surface_access,
)?)
} else {
None
};
#[allow(unsafe_code)]
let gl = {
match connection.gl_api() {
GLApi::GL => unsafe {
gl::GlFns::load_with(|s| device.get_proc_address(&context, s))
},
GLApi::GLES => unsafe {
gl::GlesFns::load_with(|s| device.get_proc_address(&context, s))
},
}
};
let device = RefCell::new(device);
let context = RefCell::new(context);
let data = RenderingContextData {
gl,
device,
context,
swap_chain,
};
Ok(SurfmanRenderingContext(Rc::new(data)))
}
pub fn create_surface(
&self,
surface_type: SurfaceType<NativeWidget>,
) -> Result<Surface, Error> {
let device = &mut self.0.device.borrow_mut();
let context = &self.0.context.borrow();
let surface_access = SurfaceAccess::GPUOnly;
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();
device.destroy_surface(context, &mut surface)
}
pub fn create_surface_texture(&self, surface: Surface) -> Result<SurfaceTexture, Error> {
let device = &self.0.device.borrow();
let context = &mut self.0.context.borrow_mut();
device
.create_surface_texture(context, surface)
.map_err(|(error, _)| error)
}
pub fn destroy_surface_texture(
&self,
surface_texture: SurfaceTexture,
) -> Result<Surface, Error> {
let device = &self.0.device.borrow();
let context = &mut self.0.context.borrow_mut();
device device
.destroy_surface_texture(context, surface_texture) .destroy_surface_texture(context, surface_texture)
.map_err(|(error, _)| error) .map_err(|(error, _)| error)
.ok()
} }
pub fn make_gl_context_current(&self) -> Result<(), Error> { fn connection(&self) -> Option<Connection> {
let device = &self.0.device.borrow(); Some(self.device.borrow().connection())
let context = &self.0.context.borrow(); }
device.make_context_current(context) }
/// A software rendering context that uses a software OpenGL implementation to render
/// Servo. This will generally have bad performance, but can be used in situations where
/// it is more convenient to have consistent, but slower display output.
///
/// The results of the render can be accessed via [`RenderingContext::read_to_image`].
pub struct SoftwareRenderingContext {
surfman_rendering_info: SurfmanRenderingContext,
swap_chain: SwapChain<Device>,
}
impl SoftwareRenderingContext {
pub fn new(size: PhysicalSize<u32>) -> Result<Self, Error> {
let connection = Connection::new()?;
let adapter = connection.create_software_adapter()?;
let surfman_rendering_info = SurfmanRenderingContext::new(&connection, &adapter)?;
let size = Size2D::new(size.width as i32, size.height as i32);
let surface = surfman_rendering_info.create_surface(SurfaceType::Generic { size })?;
surfman_rendering_info.bind_surface(surface)?;
surfman_rendering_info.make_current()?;
let swap_chain = surfman_rendering_info.create_attached_swap_chain()?;
Ok(SoftwareRenderingContext {
surfman_rendering_info,
swap_chain,
})
}
}
impl Drop for SoftwareRenderingContext {
fn drop(&mut self) {
let device = &mut self.surfman_rendering_info.device.borrow_mut();
let context = &mut self.surfman_rendering_info.context.borrow_mut();
let _ = self.swap_chain.destroy(device, context);
}
}
impl RenderingContext for SoftwareRenderingContext {
fn gl_context(&self) -> GlContext {
self.surfman_rendering_info.gl_context()
} }
pub fn swap_chain(&self) -> Result<&SwapChain<Device>, Error> { fn gl_display(&self) -> NativeDisplay {
self.0.swap_chain.as_ref().ok_or(Error::WidgetAttached) self.surfman_rendering_info.gl_display()
} }
pub fn resize(&self, size: Size2D<i32>) -> Result<(), Error> { fn prepare_for_rendering(&self) {
let device = &mut self.0.device.borrow_mut(); self.surfman_rendering_info.prepare_for_rendering();
let context = &mut self.0.context.borrow_mut();
if let Some(swap_chain) = self.0.swap_chain.as_ref() {
return swap_chain.resize(device, context, size);
}
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.resize_surface(context, &mut surface, size)?;
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})
} }
pub fn present(&self) -> Result<(), Error> { fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
let device = &mut self.0.device.borrow_mut(); self.surfman_rendering_info.read_to_image(source_rectangle)
let context = &mut self.0.context.borrow_mut();
if let Some(ref swap_chain) = self.0.swap_chain {
return swap_chain.swap_buffers(device, context, PreserveBuffer::No);
}
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.present_surface(context, &mut surface)?;
device
.bind_surface_to_context(context, surface)
.map_err(|(err, mut surface)| {
let _ = device.destroy_surface(context, &mut surface);
err
})
} }
/// Invoke a closure with the surface associated with the current front buffer. fn resize(&self, size: Size2D<i32>) {
/// This can be used to create a surfman::SurfaceTexture to blit elsewhere. let device = &mut self.surfman_rendering_info.device.borrow_mut();
pub fn with_front_buffer<F: FnOnce(&Device, Surface) -> Surface>(&self, f: F) { let context = &mut self.surfman_rendering_info.context.borrow_mut();
let device = &mut self.0.device.borrow_mut(); let _ = self.swap_chain.resize(device, context, size);
let context = &mut self.0.context.borrow_mut();
let surface = device
.unbind_surface_from_context(context)
.unwrap()
.unwrap();
let surface = f(device, surface);
device.bind_surface_to_context(context, surface).unwrap();
} }
pub fn device(&self) -> std::cell::Ref<Device> { fn present(&self) {
self.0.device.borrow() let device = &mut self.surfman_rendering_info.device.borrow_mut();
let context = &mut self.surfman_rendering_info.context.borrow_mut();
let _ = self
.swap_chain
.swap_buffers(device, context, PreserveBuffer::No);
} }
pub fn connection(&self) -> Connection { fn make_current(&self) -> Result<(), Error> {
let device = &self.0.device.borrow(); self.surfman_rendering_info.make_current()
device.connection()
} }
pub fn adapter(&self) -> Adapter { #[allow(unsafe_code)]
let device = &self.0.device.borrow(); fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
device.adapter() self.surfman_rendering_info.gl.clone()
} }
pub fn native_context(&self) -> NativeContext { fn gl_version(&self) -> GLVersion {
let device = &self.0.device.borrow(); self.surfman_rendering_info.gl_version()
let context = &self.0.context.borrow();
device.native_context(context)
} }
pub fn native_device(&self) -> NativeDevice { fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {
let device = &self.0.device.borrow(); self.surfman_rendering_info.create_texture(surface)
device.native_device()
} }
pub fn context_attributes(&self) -> ContextAttributes { fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {
let device = &self.0.device.borrow(); self.surfman_rendering_info.destroy_texture(surface_texture)
let context = &self.0.context.borrow();
let descriptor = &device.context_descriptor(context);
device.context_descriptor_attributes(descriptor)
} }
pub fn context_surface_info(&self) -> Result<Option<SurfaceInfo>, Error> { fn connection(&self) -> Option<Connection> {
let device = &self.0.device.borrow(); self.surfman_rendering_info.connection()
let context = &self.0.context.borrow(); }
device.context_surface_info(context) }
/// A [`RenderingContext`] that uses the `surfman` library to render to a
/// `raw-window-handle` identified window. `surfman` will attempt to create an
/// OpenGL context and surface for this window. This is a simple implementation
/// of the [`RenderingContext`] crate, but by default it paints to the entire window
/// surface.
///
/// If you would like to paint to only a portion of the window, consider using
/// [`OffscreenRenderingContext`] by calling [`WindowRenderingContext::offscreen_context`].
pub struct WindowRenderingContext(SurfmanRenderingContext);
impl WindowRenderingContext {
pub fn new(
display_handle: DisplayHandle,
window_handle: WindowHandle,
size: &PhysicalSize<u32>,
) -> Result<Self, Error> {
let connection = Connection::from_display_handle(display_handle)?;
let adapter = connection.create_adapter()?;
let surfman_rendering_info = SurfmanRenderingContext::new(&connection, &adapter)?;
let native_widget = connection
.create_native_widget_from_window_handle(
window_handle,
Size2D::new(size.width as i32, size.height as i32),
)
.expect("Failed to create native widget");
let surface =
surfman_rendering_info.create_surface(SurfaceType::Widget { native_widget })?;
surfman_rendering_info.bind_surface(surface)?;
surfman_rendering_info.make_current()?;
Ok(Self(surfman_rendering_info))
} }
pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo { pub fn offscreen_context(self: &Rc<Self>, size: Size2D<u32>) -> OffscreenRenderingContext {
let device = &self.0.device.borrow(); OffscreenRenderingContext::new(self.clone(), size)
device.surface_info(surface)
}
pub fn surface_texture_object(&self, surface: &SurfaceTexture) -> u32 {
let device = &self.0.device.borrow();
device
.surface_texture_object(surface)
.map(|t| t.0.get())
.unwrap_or_default()
} }
/// TODO: This can be removed when Servo switches fully to `glow.`
pub fn get_proc_address(&self, name: &str) -> *const c_void { pub fn get_proc_address(&self, name: &str) -> *const c_void {
let device = &self.0.device.borrow(); let device = &self.0.device.borrow();
let context = &self.0.context.borrow(); let context = &self.0.context.borrow();
device.get_proc_address(context, name) device.get_proc_address(context, name)
} }
pub fn unbind_native_surface_from_context(&self) -> Result<(), Error> { /// Stop rendering to the window that was used to create this `WindowRenderingContext`
/// or last set with [`Self::set_window`].
///
/// TODO: This should be removed once `WebView`s can replace their `RenderingContext`s.
pub fn take_window(&self) -> Result<(), Error> {
let device = self.0.device.borrow_mut(); let device = self.0.device.borrow_mut();
let mut context = self.0.context.borrow_mut(); let mut context = self.0.context.borrow_mut();
let mut surface = device.unbind_surface_from_context(&mut context)?.unwrap(); let mut surface = device.unbind_surface_from_context(&mut context)?.unwrap();
@ -481,12 +511,30 @@ impl SurfmanRenderingContext {
Ok(()) Ok(())
} }
pub fn bind_native_surface_to_context(&self, native_widget: NativeWidget) -> Result<(), Error> { /// Replace the window that this [`WindowRenderingContext`] renders to and give it a new
/// size.
///
/// TODO: This should be removed once `WebView`s can replace their `RenderingContext`s.
pub fn set_window(
&self,
window_handle: WindowHandle,
size: &PhysicalSize<u32>,
) -> Result<(), Error> {
let mut device = self.0.device.borrow_mut(); let mut device = self.0.device.borrow_mut();
let mut context = self.0.context.borrow_mut(); let mut context = self.0.context.borrow_mut();
let native_widget = device
.connection()
.create_native_widget_from_window_handle(
window_handle,
Size2D::new(size.width as i32, size.height as i32),
)
.expect("Failed to create native widget");
let surface_access = SurfaceAccess::GPUOnly; let surface_access = SurfaceAccess::GPUOnly;
let surface_type = SurfaceType::Widget { native_widget }; let surface_type = SurfaceType::Widget { native_widget };
let surface = device.create_surface(&context, surface_access, surface_type)?; let surface = device.create_surface(&context, surface_access, surface_type)?;
device device
.bind_surface_to_context(&mut context, surface) .bind_surface_to_context(&mut context, surface)
.map_err(|(err, mut surface)| { .map_err(|(err, mut surface)| {
@ -496,18 +544,60 @@ impl SurfmanRenderingContext {
device.make_context_current(&context)?; device.make_context_current(&context)?;
Ok(()) Ok(())
} }
}
pub fn framebuffer(&self) -> Option<NativeFramebuffer> { impl RenderingContext for WindowRenderingContext {
self.context_surface_info() fn gl_context(&self) -> GlContext {
.unwrap_or(None) self.0.gl_context()
.and_then(|info| info.framebuffer_object)
} }
/// Create a new offscreen context that is compatible with this [`SurfmanRenderingContext`]. fn gl_display(&self) -> NativeDisplay {
/// The contents of the resulting [`OffscreenRenderingContext`] are guaranteed to be blit self.0.gl_display()
/// compatible with the this context. }
pub fn offscreen_context(&self, size: Size2D<u32>) -> OffscreenRenderingContext {
OffscreenRenderingContext::new(SurfmanRenderingContext(self.0.clone()), size) fn prepare_for_rendering(&self) {
self.0.prepare_for_rendering();
}
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
self.0.read_to_image(source_rectangle)
}
fn resize(&self, size: Size2D<i32>) {
if let Err(error) = self.0.resize_surface(size) {
warn!("Error resizing surface: {error:?}");
}
}
fn present(&self) {
if let Err(error) = self.0.present_bound_surface() {
warn!("Error presenting surface: {error:?}");
}
}
fn make_current(&self) -> Result<(), Error> {
self.0.make_current()
}
#[allow(unsafe_code)]
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
self.0.gl.clone()
}
fn gl_version(&self) -> GLVersion {
self.0.gl_version()
}
fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {
self.0.create_texture(surface)
}
fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {
self.0.destroy_texture(surface_texture)
}
fn connection(&self) -> Option<Connection> {
self.0.connection()
} }
} }
@ -605,11 +695,11 @@ impl Framebuffer {
} }
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> { fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {
Self::read_framebuffer_to_image(self.gl.clone(), self.framebuffer_id, source_rectangle) Self::read_framebuffer_to_image(&self.gl, self.framebuffer_id, source_rectangle)
} }
fn read_framebuffer_to_image( fn read_framebuffer_to_image(
gl: Rc<dyn Gl>, gl: &Rc<dyn Gl>,
framebuffer_id: u32, framebuffer_id: u32,
source_rectangle: Rect<u32>, source_rectangle: Rect<u32>,
) -> Option<RgbaImage> { ) -> Option<RgbaImage> {
@ -656,7 +746,7 @@ impl Framebuffer {
} }
pub struct OffscreenRenderingContext { pub struct OffscreenRenderingContext {
parent_context: SurfmanRenderingContext, parent_context: Rc<WindowRenderingContext>,
size: Cell<Size2D<u32>>, size: Cell<Size2D<u32>>,
back_framebuffer: RefCell<Framebuffer>, back_framebuffer: RefCell<Framebuffer>,
front_framebuffer: RefCell<Option<Framebuffer>>, front_framebuffer: RefCell<Option<Framebuffer>>,
@ -665,7 +755,7 @@ pub struct OffscreenRenderingContext {
type RenderToParentCallback = Box<dyn Fn(&glow::Context, Rect<i32>) + Send + Sync>; type RenderToParentCallback = Box<dyn Fn(&glow::Context, Rect<i32>) + Send + Sync>;
impl OffscreenRenderingContext { impl OffscreenRenderingContext {
fn new(parent_context: SurfmanRenderingContext, size: Size2D<u32>) -> Self { fn new(parent_context: Rc<WindowRenderingContext>, size: Size2D<u32>) -> Self {
let next_framebuffer = Framebuffer::new(parent_context.gl_api(), size); let next_framebuffer = Framebuffer::new(parent_context.gl_api(), size);
Self { Self {
parent_context, parent_context,
@ -675,7 +765,7 @@ impl OffscreenRenderingContext {
} }
} }
pub fn parent_context(&self) -> &SurfmanRenderingContext { pub fn parent_context(&self) -> &WindowRenderingContext {
&self.parent_context &self.parent_context
} }
@ -690,7 +780,7 @@ impl OffscreenRenderingContext {
// Don't accept a `None` context for the read framebuffer. // Don't accept a `None` context for the read framebuffer.
let front_framebuffer_id = let front_framebuffer_id =
NonZeroU32::new(self.front_framebuffer_id()?).map(NativeFramebuffer)?; NonZeroU32::new(self.front_framebuffer_id()?).map(NativeFramebuffer)?;
let parent_context_framebuffer_id = self.parent_context.framebuffer(); let parent_context_framebuffer_id = self.parent_context.0.framebuffer();
let size = self.size.get(); let size = self.size.get();
Some(Box::new(move |gl, target_rect| { Some(Box::new(move |gl, target_rect| {
Self::render_framebuffer_to_parent_context( Self::render_framebuffer_to_parent_context(
@ -776,7 +866,7 @@ impl RenderingContext for OffscreenRenderingContext {
} }
fn make_current(&self) -> Result<(), surfman::Error> { fn make_current(&self) -> Result<(), surfman::Error> {
self.parent_context.make_gl_context_current() self.parent_context.make_current()
} }
fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> { fn gl_api(&self) -> Rc<dyn gleam::gl::Gl> {
@ -796,7 +886,7 @@ impl RenderingContext for OffscreenRenderingContext {
} }
fn connection(&self) -> Option<Connection> { fn connection(&self) -> Option<Connection> {
Some(self.parent_context.connection()) self.parent_context.connection()
} }
fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> { fn read_to_image(&self, source_rectangle: Rect<u32>) -> Option<RgbaImage> {

View file

@ -57,6 +57,7 @@ webxr = ["libservo/webxr"]
webgpu = ["libservo/webgpu"] webgpu = ["libservo/webgpu"]
[dependencies] [dependencies]
dpi = { workspace = true }
euclid = { workspace = true } euclid = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
libservo = { path = "../../components/servo", features = ["background_hang_monitor", "bluetooth"] } libservo = { path = "../../components/servo", features = ["background_hang_monitor", "bluetooth"] }
@ -67,6 +68,7 @@ getopts = { workspace = true }
hitrace = { workspace = true, optional = true } hitrace = { workspace = true, optional = true }
mime_guess = { workspace = true } mime_guess = { workspace = true }
url = { workspace = true } url = { workspace = true }
raw-window-handle = { workspace = true }
rustls = { workspace = true, features = ["aws-lc-rs"] } rustls = { workspace = true, features = ["aws-lc-rs"] }
tokio = { workspace = true } tokio = { workspace = true }
tracing = { workspace = true, optional = true } tracing = { workspace = true, optional = true }
@ -116,7 +118,6 @@ headers = { workspace = true }
http = { workspace = true } http = { workspace = true }
net = { path = "../../components/net" } net = { path = "../../components/net" }
net_traits = { workspace = true } net_traits = { workspace = true }
raw-window-handle = "0.6"
serde_json = { workspace = true } serde_json = { workspace = true }
shellwords = "1.0.0" shellwords = "1.0.0"
surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] } surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] }

View file

@ -12,7 +12,7 @@ use std::time::Duration;
use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D}; use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D};
use keyboard_types::{Modifiers, ShortcutMatcher}; use keyboard_types::{Modifiers, ShortcutMatcher};
use log::{debug, info, warn}; use log::{debug, info};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use servo::compositing::windowing::{ use servo::compositing::windowing::{
AnimationState, EmbedderCoordinates, WebRenderDebugOption, WindowMethods, AnimationState, EmbedderCoordinates, WebRenderDebugOption, WindowMethods,
@ -22,14 +22,13 @@ use servo::servo_config::pref;
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel}; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::webrender_api::ScrollLocation; use servo::webrender_api::ScrollLocation;
use servo::webrender_traits::rendering_context::{OffscreenRenderingContext, RenderingContext};
use servo::webrender_traits::SurfmanRenderingContext;
use servo::{ use servo::{
Cursor, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton, Cursor, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Theme, TouchAction, TouchEvent, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, OffscreenRenderingContext,
TouchEventType, TouchId, WebView, WheelDelta, WheelEvent, WheelMode, RenderingContext, Theme, TouchAction, TouchEvent, TouchEventType, TouchId, WebView, WheelDelta,
WheelEvent, WheelMode, WindowRenderingContext,
}; };
use surfman::{Connection, Context, Device, SurfaceType}; use surfman::{Context, Device};
use url::Url; use url::Url;
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
use winit::event::{ use winit::event::{
@ -69,7 +68,7 @@ pub struct Window {
/// The RenderingContext that renders directly onto the Window. This is used as /// The RenderingContext that renders directly onto the Window. This is used as
/// the target of egui rendering and also where Servo rendering results are finally /// the target of egui rendering and also where Servo rendering results are finally
/// blitted. /// blitted.
window_rendering_context: SurfmanRenderingContext, window_rendering_context: Rc<WindowRenderingContext>,
/// The `RenderingContext` of Servo itself. This is used to render Servo results /// The `RenderingContext` of Servo itself. This is used to render Servo results
/// temporarily until they can be blitted into the egui scene. /// temporarily until they can be blitted into the egui scene.
@ -125,32 +124,16 @@ impl Window {
let display_handle = event_loop let display_handle = event_loop
.display_handle() .display_handle()
.expect("could not get display handle from window"); .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 let window_handle = winit_window
.window_handle() .window_handle()
.expect("could not get window handle from window"); .expect("could not get window handle from window");
let native_widget = connection let window_rendering_context = Rc::new(
.create_native_widget_from_window_handle( WindowRenderingContext::new(display_handle, window_handle, &inner_size)
window_handle, .expect("Could not create RenderingContext for Window"),
winit_size_to_euclid_size(inner_size).to_i32().to_untyped(), );
)
.expect("Failed to create native widget");
let window_rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None)
.expect("Failed to create window RenderingContext");
let surface = window_rendering_context
.create_surface(SurfaceType::Widget { native_widget })
.expect("Failed to create surface");
window_rendering_context
.bind_surface(surface)
.expect("Failed to bind surface");
// Make sure the gl context is made current. // Make sure the gl context is made current.
window_rendering_context.make_gl_context_current().unwrap(); window_rendering_context.make_current().unwrap();
let rendering_context_size = Size2D::new(inner_size.width, inner_size.height); let rendering_context_size = Size2D::new(inner_size.width, inner_size.height);
let rendering_context = let rendering_context =
@ -633,13 +616,8 @@ impl WindowPortsMethods for Window {
WindowEvent::Resized(new_size) => { WindowEvent::Resized(new_size) => {
if self.inner_size.get() != new_size { if self.inner_size.get() != new_size {
let rendering_context_size = Size2D::new(new_size.width, new_size.height); let rendering_context_size = Size2D::new(new_size.width, new_size.height);
if let Err(error) = self self.window_rendering_context
.window_rendering_context .resize(rendering_context_size.to_i32());
.resize(rendering_context_size.to_i32())
{
warn!("Could not resize window RenderingContext: {error:?}");
}
self.inner_size.set(new_size); self.inner_size.set(new_size);
webview.notify_rendering_context_resized(); webview.notify_rendering_context_resized();
} }

View file

@ -12,9 +12,8 @@ use euclid::{Box2D, Length, Point2D, Scale, Size2D};
use servo::compositing::windowing::{AnimationState, EmbedderCoordinates, WindowMethods}; use servo::compositing::windowing::{AnimationState, EmbedderCoordinates, WindowMethods};
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntSize, DevicePixel}; use servo::webrender_api::units::{DeviceIntSize, DevicePixel};
use servo::webrender_traits::rendering_context::RenderingContext; use servo::{RenderingContext, SoftwareRenderingContext};
use servo::webrender_traits::SurfmanRenderingContext; use winit::dpi::PhysicalSize;
use surfman::Connection;
use super::app_state::RunningAppState; use super::app_state::RunningAppState;
use crate::desktop::window_trait::WindowPortsMethods; use crate::desktop::window_trait::WindowPortsMethods;
@ -27,30 +26,24 @@ pub struct Window {
inner_size: Cell<DeviceIntSize>, inner_size: Cell<DeviceIntSize>,
screen_size: Size2D<i32, DeviceIndependentPixel>, screen_size: Size2D<i32, DeviceIndependentPixel>,
window_rect: Box2D<i32, DeviceIndependentPixel>, window_rect: Box2D<i32, DeviceIndependentPixel>,
rendering_context: SurfmanRenderingContext, rendering_context: Rc<SoftwareRenderingContext>,
} }
impl Window { impl Window {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub fn new(servoshell_preferences: &ServoShellPreferences) -> Rc<dyn WindowPortsMethods> { pub fn new(servoshell_preferences: &ServoShellPreferences) -> Rc<dyn WindowPortsMethods> {
let size = servoshell_preferences.initial_window_size; let size = servoshell_preferences.initial_window_size;
let connection = Connection::new().expect("Failed to create connection");
let adapter = connection
.create_software_adapter()
.expect("Failed to create adapter");
let rendering_context = SurfmanRenderingContext::create(
&connection,
&adapter,
Some(size.to_untyped().to_i32()),
)
.expect("Failed to create WR surfman");
let device_pixel_ratio_override = servoshell_preferences.device_pixel_ratio_override; let device_pixel_ratio_override = servoshell_preferences.device_pixel_ratio_override;
let device_pixel_ratio_override: Option<Scale<f32, DeviceIndependentPixel, DevicePixel>> = let device_pixel_ratio_override: Option<Scale<f32, DeviceIndependentPixel, DevicePixel>> =
device_pixel_ratio_override.map(Scale::new); device_pixel_ratio_override.map(Scale::new);
let hidpi_factor = device_pixel_ratio_override.unwrap_or_else(Scale::identity); let hidpi_factor = device_pixel_ratio_override.unwrap_or_else(Scale::identity);
let inner_size = Cell::new((size.to_f32() * hidpi_factor).to_i32()); let inner_size = (size.to_f32() * hidpi_factor).to_i32();
let physical_size = PhysicalSize::new(inner_size.width as u32, inner_size.height as u32);
let rendering_context =
SoftwareRenderingContext::new(physical_size).expect("Failed to create WR surfman");
let window_rect = Box2D::from_origin_and_size(Point2D::zero(), size.to_i32()); let window_rect = Box2D::from_origin_and_size(Point2D::zero(), size.to_i32());
let screen_size = servoshell_preferences.screen_size_override.map_or_else( let screen_size = servoshell_preferences.screen_size_override.map_or_else(
@ -62,10 +55,10 @@ impl Window {
animation_state: Cell::new(AnimationState::Idle), animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false), fullscreen: Cell::new(false),
device_pixel_ratio_override, device_pixel_ratio_override,
inner_size, inner_size: Cell::new(inner_size),
screen_size, screen_size,
window_rect, window_rect,
rendering_context, rendering_context: Rc::new(rendering_context),
}; };
Rc::new(window) Rc::new(window)
@ -150,9 +143,7 @@ impl WindowPortsMethods for Window {
} }
fn rendering_context(&self) -> Rc<dyn RenderingContext> { fn rendering_context(&self) -> Rc<dyn RenderingContext> {
// `SurfmanRenderingContext` uses shared ownership internally so cloning it here does self.rendering_context.clone()
// not create a new one really.
Rc::new(self.rendering_context.clone())
} }
} }

View file

@ -21,8 +21,7 @@ use servo::base::id::WebViewId;
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::webrender_api::units::DevicePixel; use servo::webrender_api::units::DevicePixel;
use servo::webrender_traits::rendering_context::{OffscreenRenderingContext, RenderingContext}; use servo::{LoadStatus, OffscreenRenderingContext, RenderingContext, WebView};
use servo::{LoadStatus, WebView};
use winit::event::{ElementState, MouseButton, WindowEvent}; use winit::event::{ElementState, MouseButton, WindowEvent};
use winit::event_loop::ActiveEventLoop; use winit::event_loop::ActiveEventLoop;
use winit::window::Window; use winit::window::Window;
@ -429,7 +428,7 @@ impl Minibrowser {
.parent_context() .parent_context()
.prepare_for_rendering(); .prepare_for_rendering();
self.context.paint(window); self.context.paint(window);
let _ = self.rendering_context.parent_context().present(); self.rendering_context.parent_context().present();
} }
/// Updates the location field from the given [WebViewManager], unless the user has started /// Updates the location field from the given [WebViewManager], unless the user has started

View file

@ -11,8 +11,7 @@ use euclid::{Length, Scale};
use servo::compositing::windowing::WindowMethods; use servo::compositing::windowing::WindowMethods;
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel}; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
use servo::webrender_traits::rendering_context::RenderingContext; use servo::{Cursor, RenderingContext, WebView};
use servo::{Cursor, WebView};
use super::app_state::RunningAppState; use super::app_state::RunningAppState;

View file

@ -8,6 +8,7 @@ mod resources;
mod simpleservo; mod simpleservo;
use std::os::raw::{c_char, c_int, c_void}; use std::os::raw::{c_char, c_int, c_void};
use std::ptr::NonNull;
use std::sync::Arc; use std::sync::Arc;
use android_logger::{self, Config, FilterBuilder}; use android_logger::{self, Config, FilterBuilder};
@ -15,6 +16,9 @@ use jni::objects::{GlobalRef, JClass, JObject, JString, JValue, JValueOwned};
use jni::sys::{jboolean, jfloat, jint, jobject}; use jni::sys::{jboolean, jfloat, jint, jobject};
use jni::{JNIEnv, JavaVM}; use jni::{JNIEnv, JavaVM};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use raw_window_handle::{
AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use servo::{LoadStatus, MediaSessionActionType}; use servo::{LoadStatus, MediaSessionActionType};
use simpleservo::{ use simpleservo::{
DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState, DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState,
@ -391,12 +395,15 @@ pub extern "C" fn Java_org_servo_servoview_JNIServo_resumeCompositor<'local>(
coordinates: JObject<'local>, coordinates: JObject<'local>,
) { ) {
debug!("resumeCompositor"); debug!("resumeCompositor");
let widget = unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) }; let coords = match jni_coords_to_rust_coords(&mut env, &coordinates) {
let coords = jni_coords_to_rust_coords(&mut env, &coordinates); Ok(coords) => coords,
match coords { Err(error) => return throw(&mut env, &error),
Ok(coords) => call(&mut env, |s| s.resume_compositor(widget, coords.clone())), };
Err(error) => throw(&mut env, &error),
} let (_, window_handle) = display_and_window_handle(&mut env, &surface);
call(&mut env, |s| {
s.resume_compositor(window_handle, coords.clone())
});
} }
#[no_mangle] #[no_mangle]
@ -795,17 +802,29 @@ fn get_options<'local>(
None => None, None => None,
}; };
let native_window = let (display_handle, window_handle) = display_and_window_handle(env, surface);
unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
let opts = InitOptions { let opts = InitOptions {
args: args.unwrap_or(vec![]), args: args.unwrap_or(vec![]),
url, url,
coordinates, coordinates,
density, density,
xr_discovery: None, xr_discovery: None,
surfman_integration: simpleservo::SurfmanIntegration::Widget(native_window), window_handle,
display_handle,
}; };
Ok((opts, log, log_str, gst_debug_str)) Ok((opts, log, log_str, gst_debug_str))
} }
fn display_and_window_handle(
env: &mut JNIEnv<'_>,
surface: &JObject<'_>,
) -> (RawDisplayHandle, RawWindowHandle) {
let native_window =
unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
let native_window = NonNull::new(native_window).expect("Could not get Android window");
(
RawDisplayHandle::Android(AndroidDisplayHandle::new()),
RawWindowHandle::AndroidNdk(AndroidNdkWindowHandle::new(native_window)),
)
}

View file

@ -4,19 +4,17 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::mem; use std::mem;
use std::os::raw::c_void;
use std::rc::Rc; use std::rc::Rc;
use raw_window_handle::{DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle};
use servo::compositing::CompositeTarget; use servo::compositing::CompositeTarget;
pub use servo::webrender_api::units::DeviceIntRect; pub use servo::webrender_api::units::DeviceIntRect;
use servo::webrender_traits::SurfmanRenderingContext;
/// The EventLoopWaker::wake function will be called from any thread. /// The EventLoopWaker::wake function will be called from any thread.
/// It will be called to notify embedder that some events are available, /// It will be called to notify embedder that some events are available,
/// and that perform_updates need to be called /// and that perform_updates need to be called
pub use servo::EventLoopWaker; pub use servo::EventLoopWaker;
use servo::{self, resources, Servo}; use servo::{self, resources, Servo};
pub use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult}; pub use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult, WindowRenderingContext};
use surfman::{Connection, SurfaceType};
use crate::egl::android::resources::ResourceReaderInstance; use crate::egl::android::resources::ResourceReaderInstance;
use crate::egl::app_state::{ use crate::egl::app_state::{
@ -36,13 +34,8 @@ pub struct InitOptions {
pub density: f32, pub density: f32,
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
pub xr_discovery: Option<servo::webxr::Discovery>, pub xr_discovery: Option<servo::webxr::Discovery>,
pub surfman_integration: SurfmanIntegration, pub window_handle: RawWindowHandle,
} pub display_handle: RawDisplayHandle,
/// Controls how this embedding's rendering will integrate with the embedder.
pub enum SurfmanIntegration {
/// Render directly to a provided native widget (see surfman::NativeWidget).
Widget(*mut c_void),
} }
/// Initialize Servo. At that point, we need a valid GL context. /// Initialize Servo. At that point, we need a valid GL context.
@ -70,30 +63,20 @@ pub fn init(
crate::init_tracing(servoshell_preferences.tracing_filter.as_deref()); crate::init_tracing(servoshell_preferences.tracing_filter.as_deref());
// Initialize surfman let (display_handle, window_handle) = unsafe {
let connection = Connection::new().or(Err("Failed to create connection"))?; (
let adapter = connection DisplayHandle::borrow_raw(init_opts.display_handle),
.create_adapter() WindowHandle::borrow_raw(init_opts.window_handle),
.or(Err("Failed to create adapter"))?; )
let surface_type = match init_opts.surfman_integration {
SurfmanIntegration::Widget(native_widget) => {
let native_widget = unsafe {
connection.create_native_widget_from_ptr(
native_widget,
init_opts.coordinates.framebuffer.to_untyped(),
)
};
SurfaceType::Widget { native_widget }
},
}; };
let rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None) let rendering_context = Rc::new(
.or(Err("Failed to create surface manager"))?; WindowRenderingContext::new(
let surface = rendering_context display_handle,
.create_surface(surface_type) window_handle,
.or(Err("Failed to create surface"))?; &init_opts.coordinates.framebuffer_size(),
rendering_context )
.bind_surface(surface) .expect("Could not create RenderingContext"),
.or(Err("Failed to bind surface"))?; );
let window_callbacks = Rc::new(ServoWindowCallbacks::new( let window_callbacks = Rc::new(ServoWindowCallbacks::new(
callbacks, callbacks,
@ -110,7 +93,7 @@ pub fn init(
let servo = Servo::new( let servo = Servo::new(
opts, opts,
preferences, preferences,
Rc::new(rendering_context.clone()), rendering_context.clone(),
embedder_callbacks, embedder_callbacks,
window_callbacks.clone(), window_callbacks.clone(),
None, None,

View file

@ -3,12 +3,13 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::{Ref, RefCell, RefMut}; use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use std::os::raw::c_void;
use std::rc::Rc; use std::rc::Rc;
use dpi::PhysicalSize;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use keyboard_types::{CompositionEvent, CompositionState}; use keyboard_types::{CompositionEvent, CompositionState};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use raw_window_handle::{RawWindowHandle, WindowHandle};
use servo::base::id::WebViewId; use servo::base::id::WebViewId;
use servo::compositing::windowing::{ use servo::compositing::windowing::{
AnimationState, EmbedderCoordinates, EmbedderMethods, WindowMethods, AnimationState, EmbedderCoordinates, EmbedderMethods, WindowMethods,
@ -17,14 +18,13 @@ use servo::euclid::{Box2D, Point2D, Rect, Scale, Size2D, Vector2D};
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel, DeviceRect}; use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel, DeviceRect};
use servo::webrender_api::ScrollLocation; use servo::webrender_api::ScrollLocation;
use servo::webrender_traits::SurfmanRenderingContext;
use servo::{ use servo::{
AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent, AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent,
InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType,
MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent,
NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult,
ServoDelegate, ServoError, TouchAction, TouchEvent, TouchEventType, TouchId, WebView, RenderingContext, Servo, ServoDelegate, ServoError, TouchAction, TouchEvent, TouchEventType,
WebViewDelegate, TouchId, WebView, WebViewDelegate, WindowRenderingContext,
}; };
use url::Url; use url::Url;
@ -51,6 +51,13 @@ impl Coordinates {
framebuffer: Size2D::new(fb_width, fb_height), framebuffer: Size2D::new(fb_width, fb_height),
} }
} }
pub(crate) fn framebuffer_size(&self) -> PhysicalSize<u32> {
PhysicalSize::new(
self.framebuffer.width as u32,
self.framebuffer.height as u32,
)
}
} }
pub(super) struct ServoWindowCallbacks { pub(super) struct ServoWindowCallbacks {
@ -75,7 +82,7 @@ impl ServoWindowCallbacks {
pub struct RunningAppState { pub struct RunningAppState {
servo: Servo, servo: Servo,
rendering_context: SurfmanRenderingContext, rendering_context: Rc<WindowRenderingContext>,
callbacks: Rc<ServoWindowCallbacks>, callbacks: Rc<ServoWindowCallbacks>,
inner: RefCell<RunningAppStateInner>, inner: RefCell<RunningAppStateInner>,
/// servoshell specific preferences created during startup of the application. /// servoshell specific preferences created during startup of the application.
@ -283,7 +290,7 @@ impl WebViewDelegate for RunningAppState {
impl RunningAppState { impl RunningAppState {
pub(super) fn new( pub(super) fn new(
initial_url: Option<String>, initial_url: Option<String>,
rendering_context: SurfmanRenderingContext, rendering_context: Rc<WindowRenderingContext>,
servo: Servo, servo: Servo,
callbacks: Rc<ServoWindowCallbacks>, callbacks: Rc<ServoWindowCallbacks>,
servoshell_preferences: ServoShellPreferences, servoshell_preferences: ServoShellPreferences,
@ -367,12 +374,6 @@ impl RunningAppState {
self.servo.deinit(); self.servo.deinit();
} }
/// Returns the webrender surface management integration interface.
/// This provides the embedder access to the current front buffer.
pub fn surfman(&self) -> SurfmanRenderingContext {
self.rendering_context.clone()
}
/// This is the Servo heartbeat. This needs to be called /// This is the Servo heartbeat. This needs to be called
/// everytime wakeup is called or when embedder wants Servo /// everytime wakeup is called or when embedder wants Servo
/// to act on its pending events. /// to act on its pending events.
@ -429,10 +430,8 @@ impl RunningAppState {
pub fn resize(&self, coordinates: Coordinates) { pub fn resize(&self, coordinates: Coordinates) {
info!("resize to {:?}", coordinates); info!("resize to {:?}", coordinates);
let size = coordinates.viewport.size; let size = coordinates.viewport.size;
let _ = self self.rendering_context
.rendering_context .resize(Size2D::new(size.width, size.height));
.resize(Size2D::new(size.width, size.height))
.inspect_err(|e| error!("Failed to resize rendering context: {e:?}"));
*self.callbacks.coordinates.borrow_mut() = coordinates; *self.callbacks.coordinates.borrow_mut() = coordinates;
self.active_webview().notify_rendering_context_resized(); self.active_webview().notify_rendering_context_resized();
self.active_webview() self.active_webview()
@ -632,24 +631,17 @@ impl RunningAppState {
} }
pub fn pause_compositor(&self) { pub fn pause_compositor(&self) {
if let Err(e) = self.rendering_context.unbind_native_surface_from_context() { if let Err(e) = self.rendering_context.take_window() {
warn!("Unbinding native surface from context failed ({:?})", e); warn!("Unbinding native surface from context failed ({:?})", e);
} }
self.perform_updates(); self.perform_updates();
} }
pub fn resume_compositor(&self, native_surface: *mut c_void, coords: Coordinates) { pub fn resume_compositor(&self, window_handle: RawWindowHandle, coords: Coordinates) {
if native_surface.is_null() { let window_handle = unsafe { WindowHandle::borrow_raw(window_handle) };
panic!("null passed for native_surface");
}
let connection = self.rendering_context.connection();
let native_widget = unsafe {
connection
.create_native_widget_from_ptr(native_surface, coords.framebuffer.to_untyped())
};
if let Err(e) = self if let Err(e) = self
.rendering_context .rendering_context
.bind_native_surface_to_context(native_widget) .set_window(window_handle, &coords.framebuffer_size())
{ {
warn!("Binding native surface to context failed ({:?})", e); warn!("Binding native surface to context failed ({:?})", e);
} }
@ -688,6 +680,7 @@ impl RunningAppState {
pub fn present_if_needed(&self) { pub fn present_if_needed(&self) {
if self.inner().need_present { if self.inner().need_present {
self.inner_mut().need_present = false; self.inner_mut().need_present = false;
self.active_webview().paint_immediately();
self.servo.present(); self.servo.present();
} }
} }

View file

@ -2,20 +2,22 @@
* 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/. */
use std::cell::RefCell; use std::cell::RefCell;
use std::convert::TryInto;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::path::PathBuf; use std::path::PathBuf;
use std::ptr::NonNull;
use std::rc::Rc; use std::rc::Rc;
use log::{debug, info}; use log::{debug, info};
use raw_window_handle::{
DisplayHandle, OhosDisplayHandle, OhosNdkWindowHandle, RawDisplayHandle, RawWindowHandle,
WindowHandle,
};
use servo::compositing::CompositeTarget; use servo::compositing::CompositeTarget;
use servo::webrender_traits::SurfmanRenderingContext;
/// The EventLoopWaker::wake function will be called from any thread. /// The EventLoopWaker::wake function will be called from any thread.
/// It will be called to notify embedder that some events are available, /// It will be called to notify embedder that some events are available,
/// and that perform_updates need to be called /// and that perform_updates need to be called
pub use servo::EventLoopWaker; pub use servo::EventLoopWaker;
use servo::{self, resources, Servo}; use servo::{self, resources, Servo, WindowRenderingContext};
use surfman::{Connection, SurfaceType};
use xcomponent_sys::OH_NativeXComponent; use xcomponent_sys::OH_NativeXComponent;
use crate::egl::app_state::{ use crate::egl::app_state::{
@ -62,43 +64,39 @@ pub fn init(
crate::init_tracing(servoshell_preferences.tracing_filter.as_deref()); crate::init_tracing(servoshell_preferences.tracing_filter.as_deref());
// Initialize surfman
let connection = Connection::new().or(Err("Failed to create connection"))?;
let adapter = connection
.create_adapter()
.or(Err("Failed to create adapter"))?;
let Ok(window_size) = (unsafe { super::get_xcomponent_size(xcomponent, native_window) }) else { let Ok(window_size) = (unsafe { super::get_xcomponent_size(xcomponent, native_window) }) else {
return Err("Failed to get xcomponent size"); return Err("Failed to get xcomponent size");
}; };
let coordinates = Coordinates::new(
0,
0,
window_size.width,
window_size.height,
window_size.width,
window_size.height,
);
debug!("Creating surfman widget with {window_size:?}"); let display_handle = RawDisplayHandle::Ohos(OhosDisplayHandle::new());
let native_widget = let display_handle = unsafe { DisplayHandle::borrow_raw(display_handle) };
unsafe { connection.create_native_widget_from_ptr(native_window, window_size) };
let surface_type = SurfaceType::Widget { native_widget };
info!("Creating rendering context"); let native_window = NonNull::new(native_window).expect("Could not get native window");
let rendering_context = SurfmanRenderingContext::create(&connection, &adapter, None) let window_handle = RawWindowHandle::OhosNdk(OhosNdkWindowHandle::new(native_window));
.or(Err("Failed to create surface manager"))?; let window_handle = unsafe { WindowHandle::borrow_raw(window_handle) };
let surface = rendering_context
.create_surface(surface_type) let rendering_context = Rc::new(
.or(Err("Failed to create surface"))?; WindowRenderingContext::new(
rendering_context display_handle,
.bind_surface(surface) window_handle,
.or(Err("Failed to bind surface"))?; &coordinates.framebuffer_size(),
)
.expect("Could not create RenderingContext"),
);
info!("before ServoWindowCallbacks..."); info!("before ServoWindowCallbacks...");
let window_callbacks = Rc::new(ServoWindowCallbacks::new( let window_callbacks = Rc::new(ServoWindowCallbacks::new(
callbacks, callbacks,
RefCell::new(Coordinates::new( RefCell::new(coordinates),
0,
0,
window_size.width,
window_size.height,
window_size.width,
window_size.height,
)),
options.display_density as f32, options.display_density as f32,
)); ));
@ -111,7 +109,7 @@ pub fn init(
let servo = Servo::new( let servo = Servo::new(
opts, opts,
preferences, preferences,
Rc::new(rendering_context.clone()), rendering_context.clone(),
embedder_callbacks, embedder_callbacks,
window_callbacks.clone(), window_callbacks.clone(),
None, /* user_agent */ None, /* user_agent */