mirror of
https://github.com/servo/servo.git
synced 2025-08-21 05:15:33 +01:00
Auto merge of #25853 - asajeffrey:surfmanup, r=jdm
Replace glutin by winit + surfman 0.2 <!-- Please describe your changes on the following line: --> This PR updates surfman to 0.2, and replaces glutin with winit+surfman. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes do not require tests because this should all be invisible <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
306e8ac5f9
94 changed files with 2265 additions and 1513 deletions
|
@ -53,7 +53,6 @@ clipboard = "0.5"
|
|||
euclid = "0.20"
|
||||
getopts = "0.2.11"
|
||||
gleam = "0.9"
|
||||
glutin = "0.21.0"
|
||||
keyboard-types = "0.4.3"
|
||||
lazy_static = "1"
|
||||
libservo = {path = "../../components/servo"}
|
||||
|
@ -61,19 +60,17 @@ libc = "0.2"
|
|||
log = "0.4"
|
||||
servo-media = {git = "https://github.com/servo/media"}
|
||||
shellwords = "1.0.0"
|
||||
surfman = { version = "0.2", features = ["sm-winit", "sm-x11"] }
|
||||
tinyfiledialogs = "3.0"
|
||||
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
|
||||
webxr = { git = "https://github.com/servo/webxr", features = ["ipc", "glwindow", "headless"] }
|
||||
winit = "0.19"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
|
||||
image = "0.23"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
osmesa-sys = "0.1.2"
|
||||
sig = "1.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3", features = ["wingdi", "winuser", "winnt", "winbase", "processenv", "namedpipeapi", "ntdef", "minwindef", "handleapi", "debugapi"] }
|
||||
|
||||
[target.'cfg(any(target_os = "macos", all(target_arch = "x86_64", target_os = "linux")))'.dependencies]
|
||||
osmesa-src = {git = "https://github.com/servo/osmesa-src"}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::embedder::EmbedderCallbacks;
|
|||
use crate::events_loop::EventsLoop;
|
||||
use crate::window_trait::WindowPortsMethods;
|
||||
use crate::{headed_window, headless_window};
|
||||
use glutin::WindowId;
|
||||
use winit::WindowId;
|
||||
use servo::compositing::windowing::WindowEvent;
|
||||
use servo::config::opts::{self, parse_url_or_filename};
|
||||
use servo::servo_config::pref;
|
||||
|
@ -20,6 +20,7 @@ use std::collections::HashMap;
|
|||
use std::env;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use webxr::glwindow::GlWindowDiscovery;
|
||||
|
||||
thread_local! {
|
||||
pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new());
|
||||
|
@ -35,9 +36,6 @@ pub struct App {
|
|||
|
||||
impl App {
|
||||
pub fn run(
|
||||
angle: bool,
|
||||
enable_vsync: bool,
|
||||
use_msaa: bool,
|
||||
no_native_titlebar: bool,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
user_agent: Option<String>,
|
||||
|
@ -50,21 +48,31 @@ impl App {
|
|||
} else {
|
||||
Rc::new(headed_window::Window::new(
|
||||
opts::get().initial_window_size,
|
||||
None,
|
||||
events_loop.clone(),
|
||||
angle,
|
||||
enable_vsync,
|
||||
use_msaa,
|
||||
no_native_titlebar,
|
||||
device_pixels_per_px,
|
||||
))
|
||||
};
|
||||
|
||||
let xr_discovery = if pref!(dom.webxr.glwindow) {
|
||||
let window = window.clone();
|
||||
let surfman = window.webrender_surfman();
|
||||
let events_loop = events_loop.clone();
|
||||
let factory = Box::new(move || Ok(window.new_glwindow(&*events_loop.borrow())));
|
||||
Some(GlWindowDiscovery::new(
|
||||
surfman.connection(),
|
||||
surfman.adapter(),
|
||||
surfman.context_attributes(),
|
||||
factory,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Implements embedder methods, used by libservo and constellation.
|
||||
let embedder = Box::new(EmbedderCallbacks::new(
|
||||
window.clone(),
|
||||
events_loop.clone(),
|
||||
window.gl(),
|
||||
xr_discovery,
|
||||
));
|
||||
|
||||
// Handle browser state.
|
||||
|
@ -93,36 +101,36 @@ impl App {
|
|||
}
|
||||
|
||||
// This function decides whether the event should be handled during `run_forever`.
|
||||
fn winit_event_to_servo_event(&self, event: glutin::Event) -> glutin::ControlFlow {
|
||||
fn winit_event_to_servo_event(&self, event: winit::Event) -> winit::ControlFlow {
|
||||
match event {
|
||||
// App level events
|
||||
glutin::Event::Suspended(suspended) => {
|
||||
winit::Event::Suspended(suspended) => {
|
||||
self.suspended.set(suspended);
|
||||
if !suspended {
|
||||
self.event_queue.borrow_mut().push(WindowEvent::Idle);
|
||||
}
|
||||
},
|
||||
glutin::Event::Awakened => {
|
||||
winit::Event::Awakened => {
|
||||
self.event_queue.borrow_mut().push(WindowEvent::Idle);
|
||||
},
|
||||
glutin::Event::DeviceEvent { .. } => {},
|
||||
winit::Event::DeviceEvent { .. } => {},
|
||||
|
||||
// Window level events
|
||||
glutin::Event::WindowEvent {
|
||||
winit::Event::WindowEvent {
|
||||
window_id, event, ..
|
||||
} => {
|
||||
return WINDOWS.with(|windows| {
|
||||
match windows.borrow().get(&window_id) {
|
||||
None => {
|
||||
warn!("Got an event from unknown window");
|
||||
glutin::ControlFlow::Break
|
||||
winit::ControlFlow::Break
|
||||
},
|
||||
Some(window) => {
|
||||
// Resize events need to be handled during run_forever
|
||||
let cont = if let glutin::WindowEvent::Resized(_) = event {
|
||||
glutin::ControlFlow::Continue
|
||||
let cont = if let winit::WindowEvent::Resized(_) = event {
|
||||
winit::ControlFlow::Continue
|
||||
} else {
|
||||
glutin::ControlFlow::Break
|
||||
winit::ControlFlow::Break
|
||||
};
|
||||
window.winit_event_to_servo_event(event);
|
||||
return cont;
|
||||
|
@ -131,7 +139,7 @@ impl App {
|
|||
});
|
||||
},
|
||||
}
|
||||
glutin::ControlFlow::Break
|
||||
winit::ControlFlow::Break
|
||||
}
|
||||
|
||||
fn run_loop(self) {
|
||||
|
@ -146,7 +154,7 @@ impl App {
|
|||
// If there's no animations running then we block on the window event loop.
|
||||
self.events_loop.borrow_mut().run_forever(|e| {
|
||||
let cont = self.winit_event_to_servo_event(e);
|
||||
if cont == glutin::ControlFlow::Continue {
|
||||
if cont == winit::ControlFlow::Continue {
|
||||
// Note we need to be careful to make sure that any events
|
||||
// that are handled during run_forever aren't re-entrant,
|
||||
// since we are handling them while holding onto a mutable borrow
|
||||
|
@ -237,14 +245,3 @@ pub fn register_window(window: Rc<dyn WindowPortsMethods>) {
|
|||
w.borrow_mut().insert(window.id(), window);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn gl_version(angle: bool) -> glutin::GlRequest {
|
||||
if angle {
|
||||
glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0))
|
||||
} else {
|
||||
glutin::GlRequest::GlThenGles {
|
||||
opengl_version: (3, 2),
|
||||
opengles_version: (3, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use glutin::os::ContextTraitExt;
|
||||
use glutin::{ContextBuilder, CreationError, EventsLoop, NotCurrent, PossiblyCurrent, WindowedContext, WindowBuilder};
|
||||
use servo_media::player::context::GlContext as RawContext;
|
||||
use std::os::raw;
|
||||
|
||||
pub enum GlContext {
|
||||
Current(WindowedContext<PossiblyCurrent>),
|
||||
NotCurrent(WindowedContext<NotCurrent>),
|
||||
// Used a temporary value as we switch from Current to NotCurrent.
|
||||
None,
|
||||
}
|
||||
|
||||
impl GlContext {
|
||||
pub fn window(&self) -> &glutin::Window {
|
||||
match self {
|
||||
GlContext::Current(c) => c.window(),
|
||||
GlContext::NotCurrent(c) => c.window(),
|
||||
GlContext::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn resize(&mut self, size: glutin::dpi::PhysicalSize) {
|
||||
if let GlContext::NotCurrent(_) = self {
|
||||
self.make_current();
|
||||
}
|
||||
match self {
|
||||
GlContext::Current(c) => c.resize(size),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn make_current(&mut self) {
|
||||
*self = match std::mem::replace(self, GlContext::None) {
|
||||
GlContext::Current(c) => {
|
||||
warn!("Making an already current context current");
|
||||
// Servo thinks that that this window is current,
|
||||
// but it might be wrong, since other code may have
|
||||
// changed the current GL context. Just to be on
|
||||
// the safe side, we make it current anyway.
|
||||
let c = unsafe {
|
||||
c.make_current().expect("Couldn't make window current")
|
||||
};
|
||||
GlContext::Current(c)
|
||||
},
|
||||
GlContext::NotCurrent(c) => {
|
||||
let c = unsafe {
|
||||
c.make_current().expect("Couldn't make window current")
|
||||
};
|
||||
GlContext::Current(c)
|
||||
}
|
||||
GlContext::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn make_not_current(&mut self) {
|
||||
*self = match std::mem::replace(self, GlContext::None) {
|
||||
GlContext::Current(c) => {
|
||||
let c = unsafe {
|
||||
c.make_not_current().expect("Couldn't make window not current")
|
||||
};
|
||||
GlContext::NotCurrent(c)
|
||||
},
|
||||
GlContext::NotCurrent(c) => {
|
||||
warn!("Making an already not current context not current");
|
||||
GlContext::NotCurrent(c)
|
||||
}
|
||||
GlContext::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn swap_buffers(&self) {
|
||||
match self {
|
||||
GlContext::Current(c) => {
|
||||
if let Err(err) = c.swap_buffers() {
|
||||
warn!("Failed to swap window buffers ({}).", err);
|
||||
}
|
||||
},
|
||||
GlContext::NotCurrent(_) => {
|
||||
error!("Context is not current. Forgot to call prepare_for_composite?");
|
||||
},
|
||||
GlContext::None => unreachable!(),
|
||||
};
|
||||
}
|
||||
#[allow(unreachable_code, unused_variables)]
|
||||
pub fn raw_context(&self) -> RawContext {
|
||||
match self {
|
||||
GlContext::Current(c) => {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use glutin::os::unix::RawHandle;
|
||||
|
||||
let raw_handle = unsafe { c.raw_handle() };
|
||||
return match raw_handle {
|
||||
RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
|
||||
RawHandle::Glx(handle) => RawContext::Glx(handle as usize),
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use glutin::os::windows::RawHandle;
|
||||
|
||||
let raw_handle = unsafe { c.raw_handle() };
|
||||
return match raw_handle {
|
||||
RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
|
||||
// @TODO(victor): RawContext::Wgl in servo-media
|
||||
RawHandle::Wgl(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO(victor): https://github.com/rust-windowing/glutin/pull/1221
|
||||
// https://github.com/servo/media/pull/315
|
||||
#[cfg(target_os = "macos")]
|
||||
return unimplemented!();
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "windows",
|
||||
target_os = "macos",
|
||||
)))]
|
||||
unimplemented!()
|
||||
}
|
||||
GlContext::NotCurrent(_) => {
|
||||
error!("Context is not current.");
|
||||
RawContext::Unknown
|
||||
}
|
||||
GlContext::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_window<T>(
|
||||
&self,
|
||||
cb: ContextBuilder<T>,
|
||||
wb: WindowBuilder,
|
||||
el: &EventsLoop
|
||||
) -> Result<WindowedContext<NotCurrent>, CreationError>
|
||||
where
|
||||
T: glutin::ContextCurrentState,
|
||||
{
|
||||
match self {
|
||||
GlContext::Current(ref c) => {
|
||||
cb.with_shared_lists(c).build_windowed(wb, el)
|
||||
},
|
||||
GlContext::NotCurrent(ref c) => {
|
||||
cb.with_shared_lists(c).build_windowed(wb, el)
|
||||
},
|
||||
GlContext::None => {
|
||||
cb.build_windowed(wb, el)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn egl_display(&self) -> Option<*const raw::c_void> {
|
||||
match self {
|
||||
GlContext::Current(c) => unsafe { c.get_egl_display() },
|
||||
GlContext::NotCurrent(_) => {
|
||||
error!("Context is not current.");
|
||||
None
|
||||
},
|
||||
GlContext::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_api(&self) -> glutin::Api {
|
||||
match self {
|
||||
GlContext::Current(c) => c.get_api(),
|
||||
GlContext::NotCurrent(c) => c.get_api(),
|
||||
GlContext::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,31 +5,27 @@
|
|||
//! Implements the global methods required by Servo (not window/gl/compositor related).
|
||||
|
||||
use crate::events_loop::EventsLoop;
|
||||
use crate::window_trait::WindowPortsMethods;
|
||||
use gleam::gl;
|
||||
use servo::canvas::{SurfaceProviders, WebGlExecutor};
|
||||
use servo::compositing::windowing::EmbedderMethods;
|
||||
use servo::embedder_traits::{EmbedderProxy, EventLoopWaker};
|
||||
use servo::servo_config::{opts, pref};
|
||||
use servo::servo_config::pref;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use webxr::glwindow::GlWindowDiscovery;
|
||||
|
||||
pub struct EmbedderCallbacks {
|
||||
window: Rc<dyn WindowPortsMethods>,
|
||||
events_loop: Rc<RefCell<EventsLoop>>,
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
xr_discovery: Option<GlWindowDiscovery>,
|
||||
}
|
||||
|
||||
impl EmbedderCallbacks {
|
||||
pub fn new(
|
||||
window: Rc<dyn WindowPortsMethods>,
|
||||
events_loop: Rc<RefCell<EventsLoop>>,
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
xr_discovery: Option<GlWindowDiscovery>,
|
||||
) -> EmbedderCallbacks {
|
||||
EmbedderCallbacks {
|
||||
window,
|
||||
events_loop,
|
||||
gl,
|
||||
xr_discovery,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +44,8 @@ impl EmbedderMethods for EmbedderCallbacks {
|
|||
) {
|
||||
if pref!(dom.webxr.test) {
|
||||
xr.register_mock(webxr::headless::HeadlessMockDiscovery::new());
|
||||
} else if !opts::get().headless && pref!(dom.webxr.glwindow) {
|
||||
warn!("Creating test XR device");
|
||||
let gl = self.gl.clone();
|
||||
let window = self.window.clone();
|
||||
let factory = Box::new(move || window.new_window());
|
||||
let discovery = webxr::glwindow::GlWindowDiscovery::new(gl, factory);
|
||||
xr.register(discovery);
|
||||
} else if let Some(xr_discovery) = self.xr_discovery.take() {
|
||||
xr.register(xr_discovery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! An event loop implementation that works in headless mode.
|
||||
|
||||
|
||||
use glutin;
|
||||
use winit;
|
||||
use servo::embedder_traits::EventLoopWaker;
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use std::rc::Rc;
|
||||
|
@ -14,8 +14,8 @@ use std::time;
|
|||
|
||||
#[allow(dead_code)]
|
||||
enum EventLoop {
|
||||
/// A real Glutin windowing event loop.
|
||||
Glutin(Option<glutin::EventsLoop>),
|
||||
/// A real Winit windowing event loop.
|
||||
Winit(Option<winit::EventsLoop>),
|
||||
/// A fake event loop which contains a signalling flag used to ensure
|
||||
/// that pending events get processed in a timely fashion, and a condition
|
||||
/// variable to allow waiting on that flag changing state.
|
||||
|
@ -29,14 +29,14 @@ impl EventsLoop {
|
|||
// but on Linux, the event loop requires a X11 server.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
|
||||
Rc::new(RefCell::new(EventsLoop(EventLoop::Glutin(Some(glutin::EventsLoop::new())))))
|
||||
Rc::new(RefCell::new(EventsLoop(EventLoop::Winit(Some(winit::EventsLoop::new())))))
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
|
||||
let events_loop = if headless {
|
||||
EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
|
||||
} else {
|
||||
EventLoop::Glutin(Some(glutin::EventsLoop::new()))
|
||||
EventLoop::Winit(Some(winit::EventsLoop::new()))
|
||||
};
|
||||
Rc::new(RefCell::new(EventsLoop(events_loop)))
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ impl EventsLoop {
|
|||
impl EventsLoop {
|
||||
pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
|
||||
match self.0 {
|
||||
EventLoop::Glutin(ref events_loop) => {
|
||||
EventLoop::Winit(ref events_loop) => {
|
||||
let events_loop = events_loop
|
||||
.as_ref()
|
||||
.expect("Can't create waker for unavailable event loop.");
|
||||
|
@ -55,17 +55,18 @@ impl EventsLoop {
|
|||
Box::new(HeadlessEventLoopWaker(data.clone())),
|
||||
}
|
||||
}
|
||||
pub fn as_winit(&self) -> &glutin::EventsLoop {
|
||||
pub fn as_winit(&self) -> &winit::EventsLoop {
|
||||
match self.0 {
|
||||
EventLoop::Glutin(Some(ref event_loop)) => event_loop,
|
||||
EventLoop::Glutin(None) | EventLoop::Headless(..) =>
|
||||
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 poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
|
||||
|
||||
pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(winit::Event) {
|
||||
match self.0 {
|
||||
EventLoop::Glutin(Some(ref mut events_loop)) => events_loop.poll_events(callback),
|
||||
EventLoop::Glutin(None) => (),
|
||||
EventLoop::Winit(Some(ref mut events_loop)) => events_loop.poll_events(callback),
|
||||
EventLoop::Winit(None) => (),
|
||||
EventLoop::Headless(ref data) => {
|
||||
// This is subtle - the use of the event loop in App::run_loop
|
||||
// optionally calls run_forever, then always calls poll_events.
|
||||
|
@ -80,9 +81,9 @@ impl EventsLoop {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow {
|
||||
pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(winit::Event) -> winit::ControlFlow {
|
||||
match self.0 {
|
||||
EventLoop::Glutin(ref mut events_loop) => {
|
||||
EventLoop::Winit(ref mut events_loop) => {
|
||||
let events_loop = events_loop
|
||||
.as_mut()
|
||||
.expect("Can't run an unavailable event loop.");
|
||||
|
@ -92,7 +93,7 @@ impl EventsLoop {
|
|||
let &(ref flag, ref condvar) = &**data;
|
||||
while !*flag.lock().unwrap() {
|
||||
self.sleep(flag, condvar);
|
||||
if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break {
|
||||
if callback(winit::Event::Awakened) == winit::ControlFlow::Break {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -115,10 +116,10 @@ impl EventsLoop {
|
|||
}
|
||||
|
||||
struct HeadedEventLoopWaker {
|
||||
proxy: Arc<glutin::EventsLoopProxy>,
|
||||
proxy: Arc<winit::EventsLoopProxy>,
|
||||
}
|
||||
impl HeadedEventLoopWaker {
|
||||
fn new(events_loop: &glutin::EventsLoop) -> HeadedEventLoopWaker {
|
||||
fn new(events_loop: &winit::EventsLoop) -> HeadedEventLoopWaker {
|
||||
let proxy = Arc::new(events_loop.create_proxy());
|
||||
HeadedEventLoopWaker { proxy }
|
||||
}
|
||||
|
|
|
@ -2,27 +2,21 @@
|
|||
* 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/. */
|
||||
|
||||
//! A glutin window implementation.
|
||||
//! A winit window implementation.
|
||||
|
||||
use crate::app;
|
||||
use crate::context::GlContext;
|
||||
use crate::events_loop::EventsLoop;
|
||||
use crate::keyutils::keyboard_event_from_winit;
|
||||
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
|
||||
use euclid::{
|
||||
Angle, default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit,
|
||||
Angle, Point2D, Rotation3D, Scale, Size2D, UnknownUnit,
|
||||
Vector2D, Vector3D,
|
||||
};
|
||||
use gleam::gl;
|
||||
use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
|
||||
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
|
||||
#[cfg(target_os = "macos")]
|
||||
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
|
||||
#[cfg(target_os = "linux")]
|
||||
use glutin::os::unix::WindowExt;
|
||||
use glutin::Api;
|
||||
use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
use glutin::Icon;
|
||||
use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
use winit::Icon;
|
||||
use winit::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
use image;
|
||||
use keyboard_types::{Key, KeyState, KeyboardEvent};
|
||||
|
@ -30,22 +24,32 @@ use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEven
|
|||
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
|
||||
use servo::embedder_traits::Cursor;
|
||||
use servo::script_traits::{TouchEventType, WheelMode, WheelDelta};
|
||||
use servo::servo_config::{opts, pref};
|
||||
use servo::servo_config::opts;
|
||||
use servo::servo_config::pref;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::style_traits::DevicePixel;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||
use servo::webrender_surfman::WebrenderSurfman;
|
||||
use servo_media::player::context::{GlApi, GlContext as PlayerGLContext, NativeDisplay};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
#[cfg(target_os = "linux")]
|
||||
use surfman::platform::generic::multi::connection::NativeConnection;
|
||||
#[cfg(target_os = "linux")]
|
||||
use surfman::platform::generic::multi::context::NativeContext;
|
||||
use surfman::Connection;
|
||||
use surfman::Device;
|
||||
use surfman::GLApi;
|
||||
use surfman::GLVersion;
|
||||
use surfman::NativeWidget;
|
||||
use surfman::SurfaceType;
|
||||
#[cfg(target_os = "windows")]
|
||||
use winapi;
|
||||
|
||||
const MULTISAMPLES: u16 = 16;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn builder_with_platform_options(mut builder: glutin::WindowBuilder) -> glutin::WindowBuilder {
|
||||
fn builder_with_platform_options(mut builder: winit::WindowBuilder) -> winit::WindowBuilder {
|
||||
if opts::get().output_file.is_some() {
|
||||
// Prevent the window from showing in Dock.app, stealing focus,
|
||||
// when generating an output file.
|
||||
|
@ -55,31 +59,25 @@ fn builder_with_platform_options(mut builder: glutin::WindowBuilder) -> glutin::
|
|||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn builder_with_platform_options(builder: glutin::WindowBuilder) -> glutin::WindowBuilder {
|
||||
fn builder_with_platform_options(builder: winit::WindowBuilder) -> winit::WindowBuilder {
|
||||
builder
|
||||
}
|
||||
|
||||
pub struct Window {
|
||||
gl_context: RefCell<GlContext>,
|
||||
events_loop: Rc<RefCell<EventsLoop>>,
|
||||
winit_window: winit::Window,
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
screen_size: Size2D<u32, DeviceIndependentPixel>,
|
||||
inner_size: Cell<Size2D<u32, DeviceIndependentPixel>>,
|
||||
mouse_down_button: Cell<Option<glutin::MouseButton>>,
|
||||
mouse_down_button: Cell<Option<winit::MouseButton>>,
|
||||
mouse_down_point: Cell<Point2D<i32, DevicePixel>>,
|
||||
primary_monitor: glutin::MonitorId,
|
||||
primary_monitor: winit::MonitorId,
|
||||
event_queue: RefCell<Vec<WindowEvent>>,
|
||||
mouse_pos: Cell<Point2D<i32, DevicePixel>>,
|
||||
last_pressed: Cell<Option<KeyboardEvent>>,
|
||||
animation_state: Cell<AnimationState>,
|
||||
fullscreen: Cell<bool>,
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
|
||||
xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
|
||||
angle: bool,
|
||||
enable_vsync: bool,
|
||||
use_msaa: bool,
|
||||
no_native_titlebar: bool,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
xr_window_poses: RefCell<Vec<Rc<XRWindowPose>>>,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
@ -97,11 +95,7 @@ fn window_creation_scale_factor() -> Scale<f32, DeviceIndependentPixel, DevicePi
|
|||
impl Window {
|
||||
pub fn new(
|
||||
win_size: Size2D<u32, DeviceIndependentPixel>,
|
||||
sharing: Option<&Window>,
|
||||
events_loop: Rc<RefCell<EventsLoop>>,
|
||||
angle: bool,
|
||||
enable_vsync: bool,
|
||||
use_msaa: bool,
|
||||
no_native_titlebar: bool,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
) -> Window {
|
||||
|
@ -117,7 +111,7 @@ impl Window {
|
|||
let width = win_size.to_untyped().width;
|
||||
let height = win_size.to_untyped().height;
|
||||
|
||||
let mut window_builder = glutin::WindowBuilder::new()
|
||||
let mut window_builder = winit::WindowBuilder::new()
|
||||
.with_title("Servo".to_string())
|
||||
.with_decorations(!no_native_titlebar)
|
||||
.with_transparency(no_native_titlebar)
|
||||
|
@ -127,39 +121,14 @@ impl Window {
|
|||
|
||||
window_builder = builder_with_platform_options(window_builder);
|
||||
|
||||
let mut context_builder = glutin::ContextBuilder::new()
|
||||
.with_gl(app::gl_version(angle))
|
||||
.with_vsync(enable_vsync);
|
||||
|
||||
if use_msaa {
|
||||
context_builder = context_builder.with_multisampling(MULTISAMPLES)
|
||||
}
|
||||
|
||||
let context = match sharing {
|
||||
Some(sharing) => sharing.gl_context.borrow().new_window(
|
||||
context_builder,
|
||||
window_builder,
|
||||
events_loop.borrow().as_winit()
|
||||
),
|
||||
None => context_builder.build_windowed(window_builder, events_loop.borrow().as_winit()),
|
||||
}.expect("Failed to create window.");
|
||||
let winit_window = window_builder.build(events_loop.borrow().as_winit()).expect("Failed to create window.");
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
{
|
||||
let icon_bytes = include_bytes!("../../resources/servo64.png");
|
||||
context.window().set_window_icon(Some(load_icon(icon_bytes)));
|
||||
winit_window.set_window_icon(Some(load_icon(icon_bytes)));
|
||||
}
|
||||
|
||||
if let Some(sharing) = sharing {
|
||||
debug!("Making window {:?} not current", sharing.gl_context.borrow().window().id());
|
||||
sharing.gl_context.borrow_mut().make_not_current();
|
||||
}
|
||||
|
||||
let context = unsafe {
|
||||
debug!("Making window {:?} current", context.window().id());
|
||||
context.make_current().expect("Couldn't make window current")
|
||||
};
|
||||
|
||||
let primary_monitor = events_loop.borrow().as_winit().get_primary_monitor();
|
||||
|
||||
let PhysicalSize {
|
||||
|
@ -168,59 +137,43 @@ impl Window {
|
|||
} = primary_monitor.get_dimensions();
|
||||
let screen_size = Size2D::new(screen_width as u32, screen_height as u32);
|
||||
// TODO(ajeffrey): can this fail?
|
||||
let LogicalSize { width, height } = context
|
||||
.window()
|
||||
let LogicalSize { width, height } = winit_window
|
||||
.get_inner_size()
|
||||
.expect("Failed to get window inner size.");
|
||||
let inner_size = Size2D::new(width as u32, height as u32);
|
||||
|
||||
context.window().show();
|
||||
winit_window.show();
|
||||
|
||||
let gl = if let Some(sharing) = sharing {
|
||||
sharing.gl.clone()
|
||||
} else { match context.get_api() {
|
||||
Api::OpenGl => unsafe {
|
||||
gl::GlFns::load_with(|s| context.get_proc_address(s) as *const _)
|
||||
},
|
||||
Api::OpenGlEs => unsafe {
|
||||
gl::GlesFns::load_with(|s| context.get_proc_address(s) as *const _)
|
||||
},
|
||||
Api::WebGl => unreachable!("webgl is unsupported"),
|
||||
} };
|
||||
// Initialize surfman
|
||||
let connection = Connection::from_winit_window(&winit_window).expect("Failed to create connection");
|
||||
let adapter = connection.create_adapter().expect("Failed to create adapter");
|
||||
let native_widget = connection
|
||||
.create_native_widget_from_winit_window(&winit_window)
|
||||
.expect("Failed to create native widget");
|
||||
let surface_type = SurfaceType::Widget { native_widget };
|
||||
let webrender_surfman = WebrenderSurfman::create(
|
||||
&connection,
|
||||
&adapter,
|
||||
surface_type,
|
||||
).expect("Failed to create WR surfman");
|
||||
|
||||
gl.clear_color(0.6, 0.6, 0.6, 1.0);
|
||||
gl.clear(gl::COLOR_BUFFER_BIT);
|
||||
gl.finish();
|
||||
|
||||
let context = GlContext::Current(context);
|
||||
|
||||
debug!("Created window {:?}", context.window().id());
|
||||
let window = Window {
|
||||
gl_context: RefCell::new(context),
|
||||
events_loop,
|
||||
debug!("Created window {:?}", winit_window.id());
|
||||
Window {
|
||||
winit_window,
|
||||
webrender_surfman,
|
||||
event_queue: RefCell::new(vec![]),
|
||||
mouse_down_button: Cell::new(None),
|
||||
mouse_down_point: Cell::new(Point2D::new(0, 0)),
|
||||
mouse_pos: Cell::new(Point2D::new(0, 0)),
|
||||
last_pressed: Cell::new(None),
|
||||
gl: gl.clone(),
|
||||
animation_state: Cell::new(AnimationState::Idle),
|
||||
fullscreen: Cell::new(false),
|
||||
inner_size: Cell::new(inner_size),
|
||||
primary_monitor,
|
||||
screen_size,
|
||||
xr_rotation: Cell::new(Rotation3D::identity()),
|
||||
xr_translation: Cell::new(Vector3D::zero()),
|
||||
angle,
|
||||
enable_vsync,
|
||||
use_msaa,
|
||||
no_native_titlebar,
|
||||
device_pixels_per_px,
|
||||
};
|
||||
|
||||
window.present();
|
||||
|
||||
window
|
||||
xr_window_poses: RefCell::new(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_received_character(&self, mut ch: char) {
|
||||
|
@ -245,7 +198,10 @@ impl Window {
|
|||
KeyboardEvent::default()
|
||||
};
|
||||
event.key = Key::Character(ch.to_string());
|
||||
self.handle_xr_translation(&event);
|
||||
let xr_poses = self.xr_window_poses.borrow();
|
||||
for xr_window_pose in &*xr_poses {
|
||||
xr_window_pose.handle_xr_translation(&event);
|
||||
}
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push(WindowEvent::Keyboard(event));
|
||||
|
@ -258,68 +214,21 @@ impl Window {
|
|||
self.last_pressed.set(Some(event));
|
||||
} else if event.key != Key::Unidentified {
|
||||
self.last_pressed.set(None);
|
||||
self.handle_xr_rotation(&input);
|
||||
let xr_poses = self.xr_window_poses.borrow();
|
||||
for xr_window_pose in &*xr_poses {
|
||||
xr_window_pose.handle_xr_rotation(&input);
|
||||
}
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push(WindowEvent::Keyboard(event));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_xr_translation(&self, input: &KeyboardEvent) {
|
||||
if input.state != KeyState::Down {
|
||||
return;
|
||||
}
|
||||
const NORMAL_TRANSLATE: f32 = 0.1;
|
||||
const QUICK_TRANSLATE: f32 = 1.0;
|
||||
let mut x = 0.0;
|
||||
let mut z = 0.0;
|
||||
match input.key {
|
||||
Key::Character(ref k) => match &**k {
|
||||
"w" => z = -NORMAL_TRANSLATE,
|
||||
"W" => z = -QUICK_TRANSLATE,
|
||||
"s" => z = NORMAL_TRANSLATE,
|
||||
"S" => z = QUICK_TRANSLATE,
|
||||
"a" => x = -NORMAL_TRANSLATE,
|
||||
"A" => x = -QUICK_TRANSLATE,
|
||||
"d" => x = NORMAL_TRANSLATE,
|
||||
"D" => x = QUICK_TRANSLATE,
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
let (old_x, old_y, old_z) = self.xr_translation.get().to_tuple();
|
||||
let vec = Vector3D::new(x + old_x, old_y, z + old_z);
|
||||
self.xr_translation.set(vec);
|
||||
}
|
||||
|
||||
fn handle_xr_rotation(&self, input: &KeyboardInput) {
|
||||
if input.state != glutin::ElementState::Pressed {
|
||||
return;
|
||||
}
|
||||
let mut x = 0.0;
|
||||
let mut y = 0.0;
|
||||
match input.virtual_keycode {
|
||||
Some(VirtualKeyCode::Up) => x = 1.0,
|
||||
Some(VirtualKeyCode::Down) => x = -1.0,
|
||||
Some(VirtualKeyCode::Left) => y = 1.0,
|
||||
Some(VirtualKeyCode::Right) => y = -1.0,
|
||||
_ => return,
|
||||
};
|
||||
if input.modifiers.shift {
|
||||
x = 10.0 * x;
|
||||
y = 10.0 * y;
|
||||
}
|
||||
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
|
||||
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
|
||||
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
|
||||
self.xr_rotation.set(rotation);
|
||||
}
|
||||
|
||||
/// Helper function to handle a click
|
||||
fn handle_mouse(
|
||||
&self,
|
||||
button: glutin::MouseButton,
|
||||
action: glutin::ElementState,
|
||||
button: winit::MouseButton,
|
||||
action: winit::ElementState,
|
||||
coords: Point2D<i32, DevicePixel>,
|
||||
) {
|
||||
use servo::script_traits::MouseButton;
|
||||
|
@ -359,7 +268,7 @@ impl Window {
|
|||
}
|
||||
|
||||
fn device_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
Scale::new(self.gl_context.borrow().window().get_hidpi_factor() as f32)
|
||||
Scale::new(self.winit_window.get_hidpi_factor() as f32)
|
||||
}
|
||||
|
||||
fn servo_hidpi_factor(&self) -> Scale<f32, DeviceIndependentPixel, DevicePixel> {
|
||||
|
@ -385,33 +294,31 @@ impl WindowPortsMethods for Window {
|
|||
fn page_height(&self) -> f32 {
|
||||
let dpr = self.servo_hidpi_factor();
|
||||
let size = self
|
||||
.gl_context
|
||||
.borrow()
|
||||
.window()
|
||||
.winit_window
|
||||
.get_inner_size()
|
||||
.expect("Failed to get window inner size.");
|
||||
size.height as f32 * dpr.get()
|
||||
}
|
||||
|
||||
fn set_title(&self, title: &str) {
|
||||
self.gl_context.borrow().window().set_title(title);
|
||||
self.winit_window.set_title(title);
|
||||
}
|
||||
|
||||
fn set_inner_size(&self, size: DeviceIntSize) {
|
||||
let size = size.to_f32() / self.device_hidpi_factor();
|
||||
self.gl_context.borrow_mut().window()
|
||||
self.winit_window
|
||||
.set_inner_size(LogicalSize::new(size.width.into(), size.height.into()))
|
||||
}
|
||||
|
||||
fn set_position(&self, point: DeviceIntPoint) {
|
||||
let point = point.to_f32() / self.device_hidpi_factor();
|
||||
self.gl_context.borrow_mut().window()
|
||||
self.winit_window
|
||||
.set_position(LogicalPosition::new(point.x.into(), point.y.into()))
|
||||
}
|
||||
|
||||
fn set_fullscreen(&self, state: bool) {
|
||||
if self.fullscreen.get() != state {
|
||||
self.gl_context.borrow_mut().window()
|
||||
self.winit_window
|
||||
.set_fullscreen(if state { Some(self.primary_monitor.clone()) } else { None });
|
||||
}
|
||||
self.fullscreen.set(state);
|
||||
|
@ -422,7 +329,7 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
|
||||
fn set_cursor(&self, cursor: Cursor) {
|
||||
use glutin::MouseCursor;
|
||||
use winit::MouseCursor;
|
||||
|
||||
let winit_cursor = match cursor {
|
||||
Cursor::Default => MouseCursor::Default,
|
||||
|
@ -461,27 +368,27 @@ impl WindowPortsMethods for Window {
|
|||
Cursor::ZoomOut => MouseCursor::ZoomOut,
|
||||
_ => MouseCursor::Default,
|
||||
};
|
||||
self.gl_context.borrow_mut().window().set_cursor(winit_cursor);
|
||||
self.winit_window.set_cursor(winit_cursor);
|
||||
}
|
||||
|
||||
fn is_animating(&self) -> bool {
|
||||
self.animation_state.get() == AnimationState::Animating
|
||||
}
|
||||
|
||||
fn id(&self) -> glutin::WindowId {
|
||||
self.gl_context.borrow().window().id()
|
||||
fn id(&self) -> winit::WindowId {
|
||||
self.winit_window.id()
|
||||
}
|
||||
|
||||
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) {
|
||||
fn winit_event_to_servo_event(&self, event: winit::WindowEvent) {
|
||||
match event {
|
||||
glutin::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch),
|
||||
glutin::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input),
|
||||
glutin::WindowEvent::MouseInput { state, button, .. } => {
|
||||
winit::WindowEvent::ReceivedCharacter(ch) => self.handle_received_character(ch),
|
||||
winit::WindowEvent::KeyboardInput { input, .. } => self.handle_keyboard_input(input),
|
||||
winit::WindowEvent::MouseInput { state, button, .. } => {
|
||||
if button == MouseButton::Left || button == MouseButton::Right {
|
||||
self.handle_mouse(button, state, self.mouse_pos.get());
|
||||
}
|
||||
},
|
||||
glutin::WindowEvent::CursorMoved { position, .. } => {
|
||||
winit::WindowEvent::CursorMoved { position, .. } => {
|
||||
let pos = position.to_physical(self.device_hidpi_factor().get() as f64);
|
||||
let (x, y): (i32, i32) = pos.into();
|
||||
self.mouse_pos.set(Point2D::new(x, y));
|
||||
|
@ -491,7 +398,7 @@ impl WindowPortsMethods for Window {
|
|||
x as f32, y as f32,
|
||||
)));
|
||||
},
|
||||
glutin::WindowEvent::MouseWheel { delta, phase, .. } => {
|
||||
winit::WindowEvent::MouseWheel { delta, phase, .. } => {
|
||||
let (mut dx, mut dy, mode) = match delta {
|
||||
MouseScrollDelta::LineDelta(dx, dy) => (dx as f64, (dy * LINE_HEIGHT) as f64,
|
||||
WheelMode::DeltaLine),
|
||||
|
@ -524,7 +431,7 @@ impl WindowPortsMethods for Window {
|
|||
self.event_queue.borrow_mut().push(wheel_event);
|
||||
self.event_queue.borrow_mut().push(scroll_event);
|
||||
},
|
||||
glutin::WindowEvent::Touch(touch) => {
|
||||
winit::WindowEvent::Touch(touch) => {
|
||||
use servo::script_traits::TouchId;
|
||||
|
||||
let phase = winit_phase_to_touch_event_type(touch.phase);
|
||||
|
@ -537,19 +444,19 @@ impl WindowPortsMethods for Window {
|
|||
.borrow_mut()
|
||||
.push(WindowEvent::Touch(phase, id, point));
|
||||
},
|
||||
glutin::WindowEvent::Refresh => {
|
||||
winit::WindowEvent::Refresh => {
|
||||
self.event_queue.borrow_mut().push(WindowEvent::Refresh);
|
||||
},
|
||||
glutin::WindowEvent::CloseRequested => {
|
||||
winit::WindowEvent::CloseRequested => {
|
||||
self.event_queue.borrow_mut().push(WindowEvent::Quit);
|
||||
},
|
||||
glutin::WindowEvent::Resized(size) => {
|
||||
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
|
||||
self.gl_context.borrow_mut().resize(physical_size);
|
||||
// window.set_inner_size() takes DeviceIndependentPixel.
|
||||
winit::WindowEvent::Resized(size) => {
|
||||
let (width, height) = size.into();
|
||||
let new_size = Size2D::new(width, height);
|
||||
if self.inner_size.get() != new_size {
|
||||
let physical_size = size.to_physical(self.device_hidpi_factor().get() as f64);
|
||||
let physical_size = Size2D::new(physical_size.width, physical_size.height);
|
||||
self.webrender_surfman.resize(physical_size.to_i32()).expect("Failed to resize");
|
||||
self.inner_size.set(new_size);
|
||||
self.event_queue.borrow_mut().push(WindowEvent::Resize);
|
||||
}
|
||||
|
@ -557,75 +464,40 @@ impl WindowPortsMethods for Window {
|
|||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl webxr::glwindow::GlWindow for Window {
|
||||
fn make_current(&self) {
|
||||
debug!("Making window {:?} current", self.gl_context.borrow().window().id());
|
||||
self.gl_context.borrow_mut().make_current();
|
||||
}
|
||||
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> {
|
||||
let size = self.winit_window.get_outer_size()
|
||||
.expect("Failed to get window outer size");
|
||||
|
||||
fn swap_buffers(&self) {
|
||||
debug!("Swapping buffers on window {:?}", self.gl_context.borrow().window().id());
|
||||
self.gl_context.borrow().swap_buffers();
|
||||
self.gl_context.borrow_mut().make_not_current();
|
||||
}
|
||||
let mut window_builder = winit::WindowBuilder::new()
|
||||
.with_title("Servo XR".to_string())
|
||||
.with_dimensions(size)
|
||||
.with_visibility(true);
|
||||
|
||||
fn size(&self) -> UntypedSize2D<gl::GLsizei> {
|
||||
let dpr = self.device_hidpi_factor().get() as f64;
|
||||
let size = self
|
||||
.gl_context
|
||||
.borrow()
|
||||
.window()
|
||||
.get_inner_size()
|
||||
.expect("Failed to get window inner size.");
|
||||
let size = size.to_physical(dpr);
|
||||
let (w, h): (u32, u32) = size.into();
|
||||
Size2D::new(w as i32, h as i32)
|
||||
}
|
||||
window_builder = builder_with_platform_options(window_builder);
|
||||
|
||||
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
|
||||
self.xr_rotation.get().clone()
|
||||
}
|
||||
let winit_window = window_builder.build(events_loop.as_winit())
|
||||
.expect("Failed to create window.");
|
||||
|
||||
fn get_translation(&self) -> Vector3D<f32, UnknownUnit> {
|
||||
self.xr_translation.get().clone()
|
||||
}
|
||||
|
||||
fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> {
|
||||
let window = Rc::new(Window::new(
|
||||
self.inner_size.get(),
|
||||
Some(self),
|
||||
self.events_loop.clone(),
|
||||
self.angle,
|
||||
self.enable_vsync,
|
||||
self.use_msaa,
|
||||
self.no_native_titlebar,
|
||||
self.device_pixels_per_px,
|
||||
));
|
||||
app::register_window(window.clone());
|
||||
Ok(window)
|
||||
let pose = Rc::new(XRWindowPose {
|
||||
xr_rotation: Cell::new(Rotation3D::identity()),
|
||||
xr_translation: Cell::new(Vector3D::zero()),
|
||||
});
|
||||
self.xr_window_poses.borrow_mut().push(pose.clone());
|
||||
Box::new(XRWindow { winit_window, pose })
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for Window {
|
||||
fn gl(&self) -> Rc<dyn gl::Gl> {
|
||||
self.gl.clone()
|
||||
}
|
||||
|
||||
fn get_coordinates(&self) -> EmbedderCoordinates {
|
||||
// TODO(ajeffrey): can this fail?
|
||||
let dpr = self.device_hidpi_factor();
|
||||
let LogicalSize { width, height } = self
|
||||
.gl_context
|
||||
.borrow()
|
||||
.window()
|
||||
.winit_window
|
||||
.get_outer_size()
|
||||
.expect("Failed to get window outer size.");
|
||||
let LogicalPosition { x, y } = self
|
||||
.gl_context
|
||||
.borrow()
|
||||
.window()
|
||||
.winit_window
|
||||
.get_position()
|
||||
.unwrap_or(LogicalPosition::new(0., 0.));
|
||||
let win_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
|
||||
|
@ -633,45 +505,58 @@ impl WindowMethods for Window {
|
|||
let screen = (self.screen_size.to_f32() * dpr).to_i32();
|
||||
|
||||
let LogicalSize { width, height } = self
|
||||
.gl_context
|
||||
.borrow()
|
||||
.window()
|
||||
.winit_window
|
||||
.get_inner_size()
|
||||
.expect("Failed to get window inner size.");
|
||||
let inner_size = (Size2D::new(width as f32, height as f32) * dpr).to_i32();
|
||||
let viewport = DeviceIntRect::new(Point2D::zero(), inner_size);
|
||||
let framebuffer = DeviceIntSize::from_untyped(viewport.size.to_untyped());
|
||||
|
||||
EmbedderCoordinates {
|
||||
viewport,
|
||||
framebuffer,
|
||||
window: (win_size, win_origin),
|
||||
screen: screen,
|
||||
// FIXME: Glutin doesn't have API for available size. Fallback to screen size
|
||||
// FIXME: Winit doesn't have API for available size. Fallback to screen size
|
||||
screen_avail: screen,
|
||||
hidpi_factor: self.servo_hidpi_factor(),
|
||||
}
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
self.gl_context.borrow().swap_buffers();
|
||||
self.gl_context.borrow_mut().make_not_current();
|
||||
}
|
||||
|
||||
fn set_animation_state(&self, state: AnimationState) {
|
||||
self.animation_state.set(state);
|
||||
}
|
||||
|
||||
fn make_gl_context_current(&self) {
|
||||
self.gl_context.borrow_mut().make_current();
|
||||
fn webrender_surfman(&self) -> WebrenderSurfman {
|
||||
self.webrender_surfman.clone()
|
||||
}
|
||||
|
||||
fn get_gl_context(&self) -> PlayerGLContext {
|
||||
if pref!(media.glvideo.enabled) {
|
||||
return self.gl_context.borrow().raw_context();
|
||||
if !pref!(media.glvideo.enabled) {
|
||||
return PlayerGLContext::Unknown;
|
||||
}
|
||||
|
||||
return PlayerGLContext::Unknown;
|
||||
#[allow(unused_variables)]
|
||||
let native_context = self.webrender_surfman.native_context();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
return PlayerGLContext::Egl(native_context.egl_context as usize);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
return match native_context {
|
||||
NativeContext::Default(NativeContext::Default(native_context)) =>
|
||||
PlayerGLContext::Egl(native_context.egl_context as usize),
|
||||
NativeContext::Default(NativeContext::Alternate(native_context)) =>
|
||||
PlayerGLContext::Egl(native_context.egl_context as usize),
|
||||
NativeContext::Alternate(_) => unimplemented!(),
|
||||
};
|
||||
|
||||
// @TODO(victor): https://github.com/servo/media/pull/315
|
||||
#[cfg(target_os = "macos")]
|
||||
#[allow(unreachable_code)]
|
||||
return unimplemented!();
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
|
||||
return unimplemented!();
|
||||
}
|
||||
|
||||
fn get_native_display(&self) -> NativeDisplay {
|
||||
|
@ -679,48 +564,41 @@ impl WindowMethods for Window {
|
|||
return NativeDisplay::Unknown;
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
let native_connection = self.webrender_surfman.connection().native_connection();
|
||||
#[allow(unused_variables)]
|
||||
let native_device = self.webrender_surfman.native_device();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
return NativeDisplay::Egl(native_device.egl_display as usize);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if let Some(display) = self.gl_context.borrow().window().get_wayland_display() {
|
||||
return NativeDisplay::Wayland(display as usize);
|
||||
} else if let Some(display) =
|
||||
self.gl_context.borrow().window().get_xlib_display()
|
||||
{
|
||||
return NativeDisplay::X11(display as usize);
|
||||
}
|
||||
}
|
||||
return match native_connection {
|
||||
NativeConnection::Default(NativeConnection::Default(conn)) =>
|
||||
NativeDisplay::Egl(conn.0 as usize),
|
||||
NativeConnection::Default(NativeConnection::Alternate(conn)) =>
|
||||
NativeDisplay::X11(conn.x11_display as usize),
|
||||
NativeConnection::Alternate(_) => unimplemented!(),
|
||||
};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
{
|
||||
if let Some(display) = self.gl_context.borrow().egl_display() {
|
||||
return NativeDisplay::Egl(display as usize);
|
||||
}
|
||||
}
|
||||
// @TODO(victor): https://github.com/servo/media/pull/315
|
||||
#[cfg(target_os = "macos")]
|
||||
#[allow(unreachable_code)]
|
||||
return unimplemented!();
|
||||
|
||||
NativeDisplay::Unknown
|
||||
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
|
||||
return unimplemented!();
|
||||
}
|
||||
|
||||
fn get_gl_api(&self) -> GlApi {
|
||||
let api = self.gl_context.borrow().get_api();
|
||||
|
||||
let version = self.gl.get_string(gl::VERSION);
|
||||
let version = version.trim_start_matches("OpenGL ES ");
|
||||
let mut values = version.split(&['.', ' '][..]);
|
||||
let major = values
|
||||
.next()
|
||||
.and_then(|v| v.parse::<u32>().ok())
|
||||
.unwrap_or(1);
|
||||
let minor = values
|
||||
.next()
|
||||
.and_then(|v| v.parse::<u32>().ok())
|
||||
.unwrap_or(20);
|
||||
|
||||
let api = self.webrender_surfman.connection().gl_api();
|
||||
let attributes = self.webrender_surfman.context_attributes();
|
||||
let GLVersion { major, minor } = attributes.version;
|
||||
match api {
|
||||
glutin::Api::OpenGl if major >= 3 && minor >= 2 => GlApi::OpenGL3,
|
||||
glutin::Api::OpenGl => GlApi::OpenGL,
|
||||
glutin::Api::OpenGlEs if major > 1 => GlApi::Gles2,
|
||||
glutin::Api::OpenGlEs => GlApi::Gles1,
|
||||
_ => GlApi::None,
|
||||
GLApi::GL if major >= 3 && minor >= 2 => GlApi::OpenGL3,
|
||||
GLApi::GL => GlApi::OpenGL,
|
||||
GLApi::GLES if major > 1 => GlApi::Gles2,
|
||||
GLApi::GLES => GlApi::Gles1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -748,3 +626,81 @@ fn load_icon(icon_bytes: &[u8]) -> Icon {
|
|||
};
|
||||
Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to load icon")
|
||||
}
|
||||
|
||||
struct XRWindow {
|
||||
winit_window: winit::Window,
|
||||
pose: Rc<XRWindowPose>,
|
||||
}
|
||||
|
||||
struct XRWindowPose {
|
||||
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
|
||||
xr_translation: Cell<Vector3D<f32, UnknownUnit>>,
|
||||
}
|
||||
|
||||
impl webxr::glwindow::GlWindow for XRWindow {
|
||||
fn get_native_widget(&self, device: &Device) -> NativeWidget {
|
||||
device.connection()
|
||||
.create_native_widget_from_winit_window(&self.winit_window)
|
||||
.expect("Failed to create native widget")
|
||||
}
|
||||
|
||||
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
|
||||
self.pose.xr_rotation.get().clone()
|
||||
}
|
||||
|
||||
fn get_translation(&self) -> Vector3D<f32, UnknownUnit> {
|
||||
self.pose.xr_translation.get().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl XRWindowPose {
|
||||
fn handle_xr_translation(&self, input: &KeyboardEvent) {
|
||||
if input.state != KeyState::Down {
|
||||
return;
|
||||
}
|
||||
const NORMAL_TRANSLATE: f32 = 0.1;
|
||||
const QUICK_TRANSLATE: f32 = 1.0;
|
||||
let mut x = 0.0;
|
||||
let mut z = 0.0;
|
||||
match input.key {
|
||||
Key::Character(ref k) => match &**k {
|
||||
"w" => z = -NORMAL_TRANSLATE,
|
||||
"W" => z = -QUICK_TRANSLATE,
|
||||
"s" => z = NORMAL_TRANSLATE,
|
||||
"S" => z = QUICK_TRANSLATE,
|
||||
"a" => x = -NORMAL_TRANSLATE,
|
||||
"A" => x = -QUICK_TRANSLATE,
|
||||
"d" => x = NORMAL_TRANSLATE,
|
||||
"D" => x = QUICK_TRANSLATE,
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
let (old_x, old_y, old_z) = self.xr_translation.get().to_tuple();
|
||||
let vec = Vector3D::new(x + old_x, old_y, z + old_z);
|
||||
self.xr_translation.set(vec);
|
||||
}
|
||||
|
||||
fn handle_xr_rotation(&self, input: &KeyboardInput) {
|
||||
if input.state != winit::ElementState::Pressed {
|
||||
return;
|
||||
}
|
||||
let mut x = 0.0;
|
||||
let mut y = 0.0;
|
||||
match input.virtual_keycode {
|
||||
Some(VirtualKeyCode::Up) => x = 1.0,
|
||||
Some(VirtualKeyCode::Down) => x = -1.0,
|
||||
Some(VirtualKeyCode::Left) => y = 1.0,
|
||||
Some(VirtualKeyCode::Right) => y = -1.0,
|
||||
_ => return,
|
||||
};
|
||||
if input.modifiers.shift {
|
||||
x = 10.0 * x;
|
||||
y = 10.0 * y;
|
||||
}
|
||||
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
|
||||
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
|
||||
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
|
||||
self.xr_rotation.set(rotation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,93 +4,28 @@
|
|||
|
||||
//! A headless window implementation.
|
||||
|
||||
use crate::events_loop::EventsLoop;
|
||||
use crate::window_trait::WindowPortsMethods;
|
||||
use euclid::{default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
|
||||
use gleam::gl;
|
||||
use glutin;
|
||||
use euclid::{Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
|
||||
use winit;
|
||||
use servo::compositing::windowing::{AnimationState, WindowEvent};
|
||||
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::style_traits::DevicePixel;
|
||||
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize};
|
||||
use servo::webrender_api::units::DeviceIntRect;
|
||||
use servo_media::player::context as MediaPlayerCtxt;
|
||||
use servo::webrender_surfman::WebrenderSurfman;
|
||||
use std::cell::Cell;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use std::cell::RefCell;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use std::ffi::CString;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
struct HeadlessContext {
|
||||
width: u32,
|
||||
height: u32,
|
||||
context: osmesa_sys::OSMesaContext,
|
||||
buffer: RefCell<Vec<u32>>,
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
struct HeadlessContext {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl HeadlessContext {
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
fn new(width: u32, height: u32, share: Option<&HeadlessContext>) -> HeadlessContext {
|
||||
let mut attribs = Vec::new();
|
||||
|
||||
attribs.push(osmesa_sys::OSMESA_PROFILE);
|
||||
attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
|
||||
attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
|
||||
attribs.push(3);
|
||||
attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
|
||||
attribs.push(3);
|
||||
attribs.push(0);
|
||||
|
||||
let share = share.map_or(ptr::null_mut(), |share| share.context as *mut _);
|
||||
|
||||
let context = unsafe { osmesa_sys::OSMesaCreateContextAttribs(attribs.as_ptr(), share) };
|
||||
|
||||
assert!(!context.is_null());
|
||||
|
||||
HeadlessContext {
|
||||
width: width,
|
||||
height: height,
|
||||
context: context,
|
||||
buffer: RefCell::new(vec![0; (width * height) as usize]),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
fn new(width: u32, height: u32, _share: Option<&HeadlessContext>) -> HeadlessContext {
|
||||
HeadlessContext {
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
fn get_proc_address(s: &str) -> *const c_void {
|
||||
let c_str = CString::new(s).expect("Unable to create CString");
|
||||
unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
fn get_proc_address(_: &str) -> *const c_void {
|
||||
ptr::null() as *const _
|
||||
}
|
||||
}
|
||||
use surfman::Connection;
|
||||
use surfman::Device;
|
||||
use surfman::NativeWidget;
|
||||
use surfman::SurfaceType;
|
||||
|
||||
pub struct Window {
|
||||
context: HeadlessContext,
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
animation_state: Cell<AnimationState>,
|
||||
fullscreen: Cell<bool>,
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
}
|
||||
|
||||
|
@ -99,18 +34,19 @@ impl Window {
|
|||
size: Size2D<u32, DeviceIndependentPixel>,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
) -> Rc<dyn WindowPortsMethods> {
|
||||
let context = HeadlessContext::new(size.width, size.height, None);
|
||||
let gl = unsafe { gl::GlFns::load_with(|s| HeadlessContext::get_proc_address(s)) };
|
||||
|
||||
// Print some information about the headless renderer that
|
||||
// can be useful in diagnosing CI failures on build machines.
|
||||
println!("{}", gl.get_string(gl::VENDOR));
|
||||
println!("{}", gl.get_string(gl::RENDERER));
|
||||
println!("{}", gl.get_string(gl::VERSION));
|
||||
// Initialize surfman
|
||||
let connection = Connection::new().expect("Failed to create connection");
|
||||
let adapter = connection.create_software_adapter().expect("Failed to create adapter");
|
||||
let size = size.to_untyped().to_i32();
|
||||
let surface_type = SurfaceType::Generic { size };
|
||||
let webrender_surfman = WebrenderSurfman::create(
|
||||
&connection,
|
||||
&adapter,
|
||||
surface_type,
|
||||
).expect("Failed to create WR surfman");
|
||||
|
||||
let window = Window {
|
||||
context,
|
||||
gl,
|
||||
webrender_surfman,
|
||||
animation_state: Cell::new(AnimationState::Idle),
|
||||
fullscreen: Cell::new(false),
|
||||
device_pixels_per_px,
|
||||
|
@ -136,13 +72,18 @@ impl WindowPortsMethods for Window {
|
|||
false
|
||||
}
|
||||
|
||||
fn id(&self) -> glutin::WindowId {
|
||||
unsafe { glutin::WindowId::dummy() }
|
||||
fn id(&self) -> winit::WindowId {
|
||||
unsafe { winit::WindowId::dummy() }
|
||||
}
|
||||
|
||||
fn page_height(&self) -> f32 {
|
||||
let height = self.webrender_surfman
|
||||
.context_surface_info()
|
||||
.unwrap_or(None)
|
||||
.map(|info| info.size.height)
|
||||
.unwrap_or(0);
|
||||
let dpr = self.servo_hidpi_factor();
|
||||
self.context.height as f32 * dpr.get()
|
||||
height as f32 * dpr.get()
|
||||
}
|
||||
|
||||
fn set_fullscreen(&self, state: bool) {
|
||||
|
@ -157,24 +98,27 @@ impl WindowPortsMethods for Window {
|
|||
self.animation_state.get() == AnimationState::Animating
|
||||
}
|
||||
|
||||
fn winit_event_to_servo_event(&self, _event: glutin::WindowEvent) {
|
||||
fn winit_event_to_servo_event(&self, _event: winit::WindowEvent) {
|
||||
// Not expecting any winit events.
|
||||
}
|
||||
|
||||
fn new_glwindow(&self, _events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for Window {
|
||||
fn gl(&self) -> Rc<dyn gl::Gl> {
|
||||
self.gl.clone()
|
||||
}
|
||||
|
||||
fn get_coordinates(&self) -> EmbedderCoordinates {
|
||||
fn get_coordinates(&self) -> EmbedderCoordinates {
|
||||
let dpr = self.servo_hidpi_factor();
|
||||
let size = (Size2D::new(self.context.width, self.context.height).to_f32() * dpr).to_i32();
|
||||
let size = self.webrender_surfman
|
||||
.context_surface_info()
|
||||
.unwrap_or(None)
|
||||
.map(|info| Size2D::from_untyped(info.size))
|
||||
.unwrap_or(Size2D::new(0, 0));
|
||||
let viewport = DeviceIntRect::new(Point2D::zero(), size);
|
||||
let framebuffer = DeviceIntSize::from_untyped(size.to_untyped());
|
||||
EmbedderCoordinates {
|
||||
viewport,
|
||||
framebuffer,
|
||||
framebuffer: size,
|
||||
window: (size, Point2D::zero()),
|
||||
screen: size,
|
||||
screen_avail: size,
|
||||
|
@ -182,31 +126,11 @@ impl WindowMethods for Window {
|
|||
}
|
||||
}
|
||||
|
||||
fn present(&self) {}
|
||||
|
||||
fn set_animation_state(&self, state: AnimationState) {
|
||||
fn set_animation_state(&self, state: AnimationState) {
|
||||
self.animation_state.set(state);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
fn make_gl_context_current(&self) {
|
||||
unsafe {
|
||||
let mut buffer = self.context.buffer.borrow_mut();
|
||||
let ret = osmesa_sys::OSMesaMakeCurrent(
|
||||
self.context.context,
|
||||
buffer.as_mut_ptr() as *mut _,
|
||||
gl::UNSIGNED_BYTE,
|
||||
self.context.width as i32,
|
||||
self.context.height as i32,
|
||||
);
|
||||
assert_ne!(ret, 0);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
fn make_gl_context_current(&self) {}
|
||||
|
||||
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
|
||||
fn get_gl_context(&self) -> MediaPlayerCtxt::GlContext {
|
||||
MediaPlayerCtxt::GlContext::Unknown
|
||||
}
|
||||
|
||||
|
@ -217,32 +141,17 @@ impl WindowMethods for Window {
|
|||
fn get_gl_api(&self) -> MediaPlayerCtxt::GlApi {
|
||||
MediaPlayerCtxt::GlApi::None
|
||||
}
|
||||
|
||||
fn webrender_surfman(&self) -> WebrenderSurfman {
|
||||
self.webrender_surfman.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl webxr::glwindow::GlWindow for Window {
|
||||
fn make_current(&self) {}
|
||||
fn swap_buffers(&self) {}
|
||||
fn size(&self) -> UntypedSize2D<gl::GLsizei> {
|
||||
let dpr = self.servo_hidpi_factor().get();
|
||||
Size2D::new(
|
||||
(self.context.width as f32 * dpr) as gl::GLsizei,
|
||||
(self.context.height as f32 * dpr) as gl::GLsizei,
|
||||
)
|
||||
}
|
||||
fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> {
|
||||
let width = self.context.width;
|
||||
let height = self.context.height;
|
||||
let share = Some(&self.context);
|
||||
let context = HeadlessContext::new(width, height, share);
|
||||
let gl = self.gl.clone();
|
||||
Ok(Rc::new(Window {
|
||||
context,
|
||||
gl,
|
||||
animation_state: Cell::new(AnimationState::Idle),
|
||||
fullscreen: Cell::new(false),
|
||||
device_pixels_per_px: self.device_pixels_per_px,
|
||||
}))
|
||||
fn get_native_widget(&self, _device: &Device) -> NativeWidget {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
|
||||
Rotation3D::identity()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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 glutin::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
|
||||
use winit::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
|
||||
use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
|
||||
|
||||
// Some shortcuts use Cmd on Mac and Control on other systems.
|
||||
|
@ -18,7 +18,7 @@ pub const CMD_OR_ALT: Modifiers = Modifiers::META;
|
|||
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;
|
||||
|
||||
fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
|
||||
use glutin::VirtualKeyCode::*;
|
||||
use winit::VirtualKeyCode::*;
|
||||
// TODO: figure out how to map NavigateForward, NavigateBackward
|
||||
// TODO: map the remaining keys if possible
|
||||
let key = if let Some(key) = key {
|
||||
|
@ -127,7 +127,7 @@ fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
|
|||
}
|
||||
|
||||
fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location {
|
||||
use glutin::VirtualKeyCode::*;
|
||||
use winit::VirtualKeyCode::*;
|
||||
// TODO: add more numpad keys
|
||||
let key = if let Some(key) = key {
|
||||
key
|
||||
|
|
|
@ -13,7 +13,6 @@ extern crate sig;
|
|||
mod app;
|
||||
mod backtrace;
|
||||
mod browser;
|
||||
mod context;
|
||||
mod embedder;
|
||||
mod events_loop;
|
||||
mod headed_window;
|
||||
|
@ -95,12 +94,6 @@ pub fn main() {
|
|||
"clean-shutdown",
|
||||
"Do not shutdown until all threads have finished (macos only)",
|
||||
);
|
||||
opts.optflag(
|
||||
"",
|
||||
"disable-vsync",
|
||||
"Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate",
|
||||
);
|
||||
opts.optflag("", "msaa", "Use multisample antialiasing in WebRender.");
|
||||
opts.optflag("b", "no-native-titlebar", "Do not use native titlebar");
|
||||
opts.optopt("", "device-pixel-ratio", "Device pixels per px", "");
|
||||
opts.optopt(
|
||||
|
@ -170,28 +163,19 @@ pub fn main() {
|
|||
process::exit(0);
|
||||
}
|
||||
|
||||
let angle = opts_matches.opt_present("angle");
|
||||
let clean_shutdown = opts_matches.opt_present("clean-shutdown");
|
||||
let do_not_use_native_titlebar =
|
||||
opts_matches.opt_present("no-native-titlebar") || !(pref!(shell.native_titlebar.enabled));
|
||||
let enable_vsync = !opts_matches.opt_present("disable-vsync");
|
||||
let use_msaa = opts_matches.opt_present("msaa");
|
||||
let device_pixels_per_px = opts_matches.opt_str("device-pixel-ratio").map(|dppx_str| {
|
||||
dppx_str.parse().unwrap_or_else(|err| {
|
||||
error!("Error parsing option: --device-pixel-ratio ({})", err);
|
||||
process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
let user_agent = opts_matches.opt_str("u");
|
||||
|
||||
App::run(
|
||||
angle,
|
||||
enable_vsync,
|
||||
use_msaa,
|
||||
do_not_use_native_titlebar,
|
||||
device_pixels_per_px,
|
||||
user_agent,
|
||||
);
|
||||
App::run(do_not_use_native_titlebar, device_pixels_per_px, user_agent);
|
||||
|
||||
platform::deinit(clean_shutdown)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
//! Definition of Window.
|
||||
//! Implemented by headless and headed windows.
|
||||
|
||||
use glutin;
|
||||
use crate::events_loop::EventsLoop;
|
||||
use winit;
|
||||
use servo::compositing::windowing::{WindowEvent, WindowMethods};
|
||||
use servo::embedder_traits::Cursor;
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||
|
@ -13,17 +14,18 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
|||
// This should vary by zoom level and maybe actual text size (focused or under cursor)
|
||||
pub const LINE_HEIGHT: f32 = 38.0;
|
||||
|
||||
pub trait WindowPortsMethods: WindowMethods + webxr::glwindow::GlWindow {
|
||||
pub trait WindowPortsMethods: WindowMethods {
|
||||
fn get_events(&self) -> Vec<WindowEvent>;
|
||||
fn id(&self) -> glutin::WindowId;
|
||||
fn id(&self) -> winit::WindowId;
|
||||
fn has_events(&self) -> bool;
|
||||
fn page_height(&self) -> f32;
|
||||
fn get_fullscreen(&self) -> bool;
|
||||
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent);
|
||||
fn winit_event_to_servo_event(&self, event: winit::WindowEvent);
|
||||
fn is_animating(&self) -> bool;
|
||||
fn set_title(&self, _title: &str) {}
|
||||
fn set_inner_size(&self, _size: DeviceIntSize) {}
|
||||
fn set_position(&self, _point: DeviceIntPoint) {}
|
||||
fn set_fullscreen(&self, _state: bool) {}
|
||||
fn set_cursor(&self, _cursor: Cursor) {}
|
||||
fn new_glwindow(&self, events_loop: &EventsLoop) -> Box<dyn webxr::glwindow::GlWindow>;
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ lazy_static = "1.4"
|
|||
libservo = {path = "../../components/servo"}
|
||||
servo-media = {git = "https://github.com/servo/media"}
|
||||
sparkle = "0.1"
|
||||
surfman = { git = "https://github.com/pcwalton/surfman", branch = "multi" }
|
||||
surfman = { git = "https://github.com/servo/surfman" }
|
||||
surfman-chains-api = "0.2"
|
||||
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains", branch = "multi" }
|
||||
surfman-chains = { git = "https://github.com/asajeffrey/surfman-chains" }
|
||||
|
||||
[build-dependencies]
|
||||
gst-plugin-version-helper = "0.1"
|
||||
|
|
|
@ -76,35 +76,20 @@ use servo::embedder_traits::EventLoopWaker;
|
|||
use servo::msg::constellation_msg::TopLevelBrowsingContextId;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::webrender_api::units::DevicePixel;
|
||||
use servo::webrender_surfman::WebrenderSurfman;
|
||||
use servo::Servo;
|
||||
|
||||
use sparkle::gl;
|
||||
use sparkle::gl::types::GLuint;
|
||||
use sparkle::gl::Gl;
|
||||
|
||||
use surfman::connection::Connection as ConnectionAPI;
|
||||
use surfman::device::Device as DeviceAPI;
|
||||
use surfman::ContextAttributeFlags;
|
||||
use surfman::ContextAttributes;
|
||||
use surfman::GLApi;
|
||||
use surfman::GLVersion;
|
||||
use surfman::SurfaceAccess;
|
||||
use surfman::Connection;
|
||||
use surfman::Context;
|
||||
use surfman::Device;
|
||||
use surfman::SurfaceType;
|
||||
use surfman_chains::SurfmanProvider;
|
||||
use surfman_chains::SwapChain;
|
||||
use surfman_chains_api::SwapChainAPI;
|
||||
|
||||
// For the moment, we only support wayland and cgl.
|
||||
#[cfg(target_os = "macos")]
|
||||
use surfman::platform::macos::cgl::device::Device;
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
use surfman::platform::unix::wayland::device::Device;
|
||||
|
||||
type Context = <Device as DeviceAPI>::Context;
|
||||
type Connection = <Device as DeviceAPI>::Connection;
|
||||
type NativeContext = <Device as DeviceAPI>::NativeContext;
|
||||
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
|
@ -165,7 +150,7 @@ impl std::fmt::Debug for ConnectionWhichImplementsDebug {
|
|||
|
||||
#[derive(Debug)]
|
||||
enum ServoWebSrcMsg {
|
||||
Start(ConnectionWhichImplementsDebug, GLVersion, ServoUrl),
|
||||
Start(ConnectionWhichImplementsDebug, ServoUrl),
|
||||
GetSwapChain(Sender<SwapChain<Device>>),
|
||||
Resize(Size2D<i32, DevicePixel>),
|
||||
Heartbeat,
|
||||
|
@ -180,41 +165,25 @@ const DEFAULT_FRAME_DURATION: Duration = Duration::from_micros(16_667);
|
|||
|
||||
struct ServoThread {
|
||||
receiver: Receiver<ServoWebSrcMsg>,
|
||||
swap_chain: SwapChain<Device>,
|
||||
gfx: Rc<RefCell<ServoThreadGfx>>,
|
||||
servo: Servo<ServoWebSrcWindow>,
|
||||
}
|
||||
|
||||
struct ServoThreadGfx {
|
||||
device: Device,
|
||||
context: Context,
|
||||
gl: Rc<Gl>,
|
||||
}
|
||||
|
||||
impl ServoThread {
|
||||
fn new(receiver: Receiver<ServoWebSrcMsg>) -> Self {
|
||||
let (connection, version, url) = match receiver.recv() {
|
||||
Ok(ServoWebSrcMsg::Start(connection, version, url)) => (connection.0, version, url),
|
||||
let (connection, url) = match receiver.recv() {
|
||||
Ok(ServoWebSrcMsg::Start(connection, url)) => (connection.0, url),
|
||||
e => panic!("Failed to start ({:?})", e),
|
||||
};
|
||||
info!(
|
||||
"Created new servo thread (GL v{}.{} for {})",
|
||||
version.major, version.minor, url
|
||||
);
|
||||
info!("Created new servo thread for {}", url);
|
||||
let embedder = Box::new(ServoWebSrcEmbedder);
|
||||
let window = Rc::new(ServoWebSrcWindow::new(connection, version));
|
||||
let swap_chain = window.swap_chain.clone();
|
||||
let gfx = window.gfx.clone();
|
||||
let window = Rc::new(ServoWebSrcWindow::new(connection));
|
||||
|
||||
let mut servo = Servo::new(embedder, window, None);
|
||||
|
||||
let id = TopLevelBrowsingContextId::new();
|
||||
servo.handle_events(vec![WindowEvent::NewBrowser(url, id)]);
|
||||
|
||||
Self {
|
||||
receiver,
|
||||
swap_chain,
|
||||
gfx,
|
||||
servo,
|
||||
}
|
||||
Self { receiver, servo }
|
||||
}
|
||||
|
||||
fn run(&mut self) {
|
||||
|
@ -222,9 +191,7 @@ impl ServoThread {
|
|||
debug!("Servo thread handling message {:?}", msg);
|
||||
match msg {
|
||||
ServoWebSrcMsg::Start(..) => error!("Already started"),
|
||||
ServoWebSrcMsg::GetSwapChain(sender) => sender
|
||||
.send(self.swap_chain.clone())
|
||||
.expect("Failed to send swap chain"),
|
||||
ServoWebSrcMsg::GetSwapChain(sender) => self.send_swap_chain(sender),
|
||||
ServoWebSrcMsg::Resize(size) => self.resize(size),
|
||||
ServoWebSrcMsg::Heartbeat => self.servo.handle_events(vec![]),
|
||||
ServoWebSrcMsg::Stop => break,
|
||||
|
@ -233,43 +200,24 @@ impl ServoThread {
|
|||
self.servo.handle_events(vec![WindowEvent::Quit]);
|
||||
}
|
||||
|
||||
fn resize(&mut self, size: Size2D<i32, DevicePixel>) {
|
||||
{
|
||||
let mut gfx = self.gfx.borrow_mut();
|
||||
let gfx = &mut *gfx;
|
||||
self.swap_chain
|
||||
.resize(&mut gfx.device, &mut gfx.context, size.to_untyped())
|
||||
.expect("Failed to resize");
|
||||
gfx.gl.viewport(0, 0, size.width, size.height);
|
||||
let fbo = gfx
|
||||
.device
|
||||
.context_surface_info(&gfx.context)
|
||||
.expect("Failed to get context info")
|
||||
.expect("Failed to get context info")
|
||||
.framebuffer_object;
|
||||
gfx.device
|
||||
.make_context_current(&gfx.context)
|
||||
.expect("Failed to make current");
|
||||
gfx.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
|
||||
debug_assert_eq!(
|
||||
(
|
||||
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
|
||||
gfx.gl.get_error()
|
||||
),
|
||||
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
|
||||
);
|
||||
}
|
||||
self.servo.handle_events(vec![WindowEvent::Resize]);
|
||||
fn send_swap_chain(&mut self, sender: Sender<SwapChain<Device>>) {
|
||||
let swap_chain = self
|
||||
.servo
|
||||
.window()
|
||||
.webrender_surfman
|
||||
.swap_chain()
|
||||
.expect("Failed to get swap chain")
|
||||
.clone();
|
||||
sender.send(swap_chain).expect("Failed to send swap chain");
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ServoThread {
|
||||
fn drop(&mut self) {
|
||||
let mut gfx = self.gfx.borrow_mut();
|
||||
let gfx = &mut *gfx;
|
||||
self.swap_chain
|
||||
.destroy(&mut gfx.device, &mut gfx.context)
|
||||
.expect("Failed to destroy swap chain")
|
||||
fn resize(&mut self, size: Size2D<i32, DevicePixel>) {
|
||||
let _ = self
|
||||
.servo
|
||||
.window()
|
||||
.webrender_surfman
|
||||
.resize(size.to_untyped());
|
||||
self.servo.handle_events(vec![WindowEvent::Resize]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,154 +238,35 @@ impl EventLoopWaker for ServoWebSrcEmbedder {
|
|||
}
|
||||
|
||||
struct ServoWebSrcWindow {
|
||||
swap_chain: SwapChain<Device>,
|
||||
gfx: Rc<RefCell<ServoThreadGfx>>,
|
||||
gl: Rc<dyn gleam::gl::Gl>,
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
}
|
||||
|
||||
impl ServoWebSrcWindow {
|
||||
fn new(connection: Connection, version: GLVersion) -> Self {
|
||||
let flags = ContextAttributeFlags::DEPTH |
|
||||
ContextAttributeFlags::STENCIL |
|
||||
ContextAttributeFlags::ALPHA;
|
||||
let attributes = ContextAttributes { version, flags };
|
||||
|
||||
fn new(connection: Connection) -> Self {
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.expect("Failed to create adapter");
|
||||
let mut device = connection
|
||||
.create_device(&adapter)
|
||||
.expect("Failed to create device");
|
||||
let descriptor = device
|
||||
.create_context_descriptor(&attributes)
|
||||
.expect("Failed to create descriptor");
|
||||
let mut context = device
|
||||
.create_context(&descriptor)
|
||||
.expect("Failed to create context");
|
||||
|
||||
let (gleam, gl) = unsafe {
|
||||
match device.gl_api() {
|
||||
GLApi::GL => (
|
||||
gleam::gl::GlFns::load_with(|s| device.get_proc_address(&context, s)),
|
||||
Gl::gl_fns(gl::ffi_gl::Gl::load_with(|s| {
|
||||
device.get_proc_address(&context, s)
|
||||
})),
|
||||
),
|
||||
GLApi::GLES => (
|
||||
gleam::gl::GlesFns::load_with(|s| device.get_proc_address(&context, s)),
|
||||
Gl::gles_fns(gl::ffi_gles::Gles2::load_with(|s| {
|
||||
device.get_proc_address(&context, s)
|
||||
})),
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
device
|
||||
.make_context_current(&mut context)
|
||||
.expect("Failed to make context current");
|
||||
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
|
||||
let access = SurfaceAccess::GPUOnly;
|
||||
let size = Size2D::new(512, 512);
|
||||
let surface_type = SurfaceType::Generic { size };
|
||||
let surface = device
|
||||
.create_surface(&mut context, access, surface_type)
|
||||
.expect("Failed to create surface");
|
||||
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
|
||||
.expect("Failed to create surfman");
|
||||
|
||||
device
|
||||
.bind_surface_to_context(&mut context, surface)
|
||||
.expect("Failed to bind surface");
|
||||
let fbo = device
|
||||
.context_surface_info(&context)
|
||||
.expect("Failed to get context info")
|
||||
.expect("Failed to get context info")
|
||||
.framebuffer_object;
|
||||
gl.viewport(0, 0, size.width, size.height);
|
||||
gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
|
||||
gl.clear_color(0.0, 0.0, 0.0, 1.0);
|
||||
gl.clear(gl::COLOR_BUFFER_BIT);
|
||||
debug_assert_eq!(
|
||||
(gl.check_framebuffer_status(gl::FRAMEBUFFER), gl.get_error()),
|
||||
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
|
||||
);
|
||||
|
||||
let provider = Box::new(SurfmanProvider::new(access));
|
||||
let swap_chain = SwapChain::create_attached(&mut device, &mut context, provider)
|
||||
.expect("Failed to create swap chain");
|
||||
|
||||
device.make_no_context_current().unwrap();
|
||||
|
||||
let gfx = Rc::new(RefCell::new(ServoThreadGfx {
|
||||
device,
|
||||
context,
|
||||
gl,
|
||||
}));
|
||||
|
||||
Self {
|
||||
swap_chain,
|
||||
gfx,
|
||||
gl: gleam,
|
||||
}
|
||||
Self { webrender_surfman }
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowMethods for ServoWebSrcWindow {
|
||||
fn present(&self) {
|
||||
debug!("EMBEDDER present");
|
||||
let mut gfx = self.gfx.borrow_mut();
|
||||
let gfx = &mut *gfx;
|
||||
gfx.device
|
||||
.make_context_current(&mut gfx.context)
|
||||
.expect("Failed to make context current");
|
||||
debug_assert_eq!(
|
||||
(
|
||||
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
|
||||
gfx.gl.get_error()
|
||||
),
|
||||
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
|
||||
);
|
||||
self.swap_chain
|
||||
.swap_buffers(&mut gfx.device, &mut gfx.context)
|
||||
.expect("Failed to swap buffers");
|
||||
let fbo = gfx
|
||||
.device
|
||||
.context_surface_info(&gfx.context)
|
||||
.expect("Failed to get context info")
|
||||
.expect("Failed to get context info")
|
||||
.framebuffer_object;
|
||||
gfx.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
|
||||
debug_assert_eq!(
|
||||
(
|
||||
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
|
||||
gfx.gl.get_error()
|
||||
),
|
||||
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
|
||||
);
|
||||
let _ = gfx.device.make_no_context_current();
|
||||
}
|
||||
|
||||
fn make_gl_context_current(&self) {
|
||||
debug!("EMBEDDER make_context_current");
|
||||
let mut gfx = self.gfx.borrow_mut();
|
||||
let gfx = &mut *gfx;
|
||||
gfx.device
|
||||
.make_context_current(&mut gfx.context)
|
||||
.expect("Failed to make context current");
|
||||
debug!("EMBEDDER done make_context_current");
|
||||
debug_assert_eq!(
|
||||
(
|
||||
gfx.gl.check_framebuffer_status(gl::FRAMEBUFFER),
|
||||
gfx.gl.get_error()
|
||||
),
|
||||
(gl::FRAMEBUFFER_COMPLETE, gl::NO_ERROR)
|
||||
);
|
||||
}
|
||||
|
||||
fn gl(&self) -> Rc<dyn gleam::gl::Gl> {
|
||||
self.gl.clone()
|
||||
fn webrender_surfman(&self) -> WebrenderSurfman {
|
||||
self.webrender_surfman.clone()
|
||||
}
|
||||
|
||||
fn get_coordinates(&self) -> EmbedderCoordinates {
|
||||
let size = Size2D::from_untyped(self.swap_chain.size());
|
||||
let size = self
|
||||
.webrender_surfman
|
||||
.context_surface_info()
|
||||
.unwrap_or(None)
|
||||
.map(|info| Size2D::from_untyped(info.size))
|
||||
.unwrap_or(Size2D::new(0, 0));
|
||||
info!("EMBEDDER coordinates {}", size);
|
||||
let origin = Point2D::origin();
|
||||
EmbedderCoordinates {
|
||||
|
@ -658,11 +487,6 @@ impl BaseSrcImpl for ServoWebSrc {
|
|||
));
|
||||
}
|
||||
let gl_context = unsafe { GLContext::from_glib_borrow(gst_gl_context) };
|
||||
let gl_version = gl_context.get_gl_version();
|
||||
let version = GLVersion {
|
||||
major: gl_version.0 as u8,
|
||||
minor: gl_version.1 as u8,
|
||||
};
|
||||
|
||||
// Get the surfman connection on the GL thread
|
||||
let mut task = BootstrapSurfmanOnGLThread {
|
||||
|
@ -683,7 +507,6 @@ impl BaseSrcImpl for ServoWebSrc {
|
|||
// Inform servo we're starting
|
||||
let _ = self.sender.send(ServoWebSrcMsg::Start(
|
||||
ConnectionWhichImplementsDebug(connection),
|
||||
version,
|
||||
url,
|
||||
));
|
||||
Ok(())
|
||||
|
@ -784,11 +607,32 @@ impl ServoWebSrc {
|
|||
gl_context
|
||||
.activate(true)
|
||||
.expect("Failed to activate GL context");
|
||||
let native_connection =
|
||||
NativeConnection::current().expect("Failed to bootstrap native connection");
|
||||
let connection = unsafe { Connection::from_native_connection(native_connection) }
|
||||
.expect("Failed to bootstrap surfman connection");
|
||||
Some(connection)
|
||||
// TODO: support other connections on linux?
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use surfman::platform::generic::multi;
|
||||
use surfman::platform::unix::wayland;
|
||||
let native_connection = wayland::connection::NativeConnection::current()
|
||||
.expect("Failed to bootstrap native connection");
|
||||
let wayland_connection = unsafe {
|
||||
wayland::connection::Connection::from_native_connection(native_connection)
|
||||
.expect("Failed to bootstrap wayland connection")
|
||||
};
|
||||
let connection = multi::connection::Connection::Default(
|
||||
multi::connection::Connection::Default(wayland_connection),
|
||||
);
|
||||
Some(connection)
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
use surfman::connection::Connection as ConnectionAPI;
|
||||
type NativeConnection = <Connection as ConnectionAPI>::NativeConnection;
|
||||
let native_connection =
|
||||
NativeConnection::current().expect("Failed to bootstrap native connection");
|
||||
let connection = unsafe { Connection::from_native_connection(native_connection) }
|
||||
.expect("Failed to bootstrap surfman connection");
|
||||
Some(connection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -840,8 +684,21 @@ impl ServoWebSrc {
|
|||
let device = connection
|
||||
.create_device(&adapter)
|
||||
.expect("Failed to bootstrap surfman device");
|
||||
let native_context =
|
||||
NativeContext::current().expect("Failed to bootstrap native context");
|
||||
#[cfg(target_os = "linux")]
|
||||
let native_context = {
|
||||
use surfman::platform::generic::multi;
|
||||
use surfman::platform::unix::wayland;
|
||||
multi::context::NativeContext::Default(multi::context::NativeContext::Default(
|
||||
wayland::context::NativeContext::current()
|
||||
.expect("Failed to bootstrap native context"),
|
||||
))
|
||||
};
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let native_context = {
|
||||
use surfman::device::Device as DeviceAPI;
|
||||
type NativeContext = <Device as DeviceAPI>::NativeContext;
|
||||
NativeContext::current().expect("Failed to bootstrap native context")
|
||||
};
|
||||
let context = unsafe {
|
||||
device
|
||||
.create_context_from_native_context(native_context)
|
||||
|
@ -995,5 +852,3 @@ impl ServoWebSrc {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement that trait for more platforms
|
||||
|
|
|
@ -12,6 +12,7 @@ ipc-channel = "0.14"
|
|||
libservo = { path = "../../../components/servo" }
|
||||
log = "0.4"
|
||||
servo-media = { git = "https://github.com/servo/media" }
|
||||
surfman = { version = "0.2", features = ["sm-angle-default"] }
|
||||
|
||||
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
|
||||
webxr = { git = "https://github.com/servo/webxr"}
|
||||
|
|
|
@ -32,6 +32,7 @@ use servo::servo_config::{pref, set_pref};
|
|||
use servo::servo_url::ServoUrl;
|
||||
use servo::webrender_api::units::DevicePixel;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::webrender_surfman::WebrenderSurfman;
|
||||
use servo::{self, gl, BrowserId, Servo};
|
||||
use servo_media::player::context as MediaPlayerContext;
|
||||
use std::cell::RefCell;
|
||||
|
@ -39,6 +40,8 @@ use std::mem;
|
|||
use std::os::raw::c_void;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use surfman::Connection;
|
||||
use surfman::SurfaceType;
|
||||
|
||||
thread_local! {
|
||||
pub static SERVO: RefCell<Option<ServoGlue>> = RefCell::new(None);
|
||||
|
@ -58,6 +61,7 @@ pub struct InitOptions {
|
|||
pub enable_subpixel_text_antialiasing: bool,
|
||||
pub gl_context_pointer: Option<*const c_void>,
|
||||
pub native_display_pointer: Option<*const c_void>,
|
||||
pub native_widget: *mut c_void,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -84,12 +88,6 @@ impl Coordinates {
|
|||
|
||||
/// Callbacks. Implemented by embedder. Called by Servo.
|
||||
pub trait HostTrait {
|
||||
/// Will be called from the thread used for the init call.
|
||||
/// Will be called when the GL buffer has been updated.
|
||||
fn flush(&self);
|
||||
/// Will be called before drawing.
|
||||
/// Time to make the targetted GL context current.
|
||||
fn make_current(&self);
|
||||
/// Show alert.
|
||||
fn prompt_alert(&self, msg: String, trusted: bool);
|
||||
/// Ask Yes/No question.
|
||||
|
@ -211,13 +209,28 @@ pub fn init(
|
|||
gl.clear(gl::COLOR_BUFFER_BIT);
|
||||
gl.finish();
|
||||
|
||||
// Initialize surfman
|
||||
let connection = Connection::new().or(Err("Failed to create connection"))?;
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.or(Err("Failed to create adapter"))?;
|
||||
let native_widget = unsafe {
|
||||
connection.create_native_widget_from_ptr(
|
||||
init_opts.native_widget,
|
||||
init_opts.coordinates.framebuffer.to_untyped(),
|
||||
)
|
||||
};
|
||||
let surface_type = SurfaceType::Widget { native_widget };
|
||||
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
|
||||
.or(Err("Failed to create surface manager"))?;
|
||||
|
||||
let window_callbacks = Rc::new(ServoWindowCallbacks {
|
||||
host_callbacks: callbacks,
|
||||
gl: gl.clone(),
|
||||
coordinates: RefCell::new(init_opts.coordinates),
|
||||
density: init_opts.density,
|
||||
gl_context_pointer: init_opts.gl_context_pointer,
|
||||
native_display_pointer: init_opts.native_display_pointer,
|
||||
webrender_surfman,
|
||||
});
|
||||
|
||||
let embedder_callbacks = Box::new(ServoEmbedderCallbacks {
|
||||
|
@ -723,12 +736,12 @@ struct ServoEmbedderCallbacks {
|
|||
}
|
||||
|
||||
struct ServoWindowCallbacks {
|
||||
gl: Rc<dyn gl::Gl>,
|
||||
host_callbacks: Box<dyn HostTrait>,
|
||||
coordinates: RefCell<Coordinates>,
|
||||
density: f32,
|
||||
gl_context_pointer: Option<*const c_void>,
|
||||
native_display_pointer: Option<*const c_void>,
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
}
|
||||
|
||||
impl EmbedderMethods for ServoEmbedderCallbacks {
|
||||
|
@ -798,7 +811,7 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
|
|||
|
||||
struct GlThread(WebGlExecutor);
|
||||
impl webxr::openxr::GlThread for GlThread {
|
||||
fn execute(&self, runnable: Box<dyn FnOnce() + Send>) {
|
||||
fn execute(&self, runnable: Box<dyn FnOnce(&surfman::Device) + Send>) {
|
||||
let _ = self.0.send(runnable);
|
||||
}
|
||||
fn clone(&self) -> Box<dyn webxr::openxr::GlThread> {
|
||||
|
@ -835,19 +848,8 @@ impl EmbedderMethods for ServoEmbedderCallbacks {
|
|||
}
|
||||
|
||||
impl WindowMethods for ServoWindowCallbacks {
|
||||
fn make_gl_context_current(&self) {
|
||||
debug!("WindowMethods::prepare_for_composite");
|
||||
self.host_callbacks.make_current();
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
debug!("WindowMethods::present");
|
||||
self.host_callbacks.flush();
|
||||
}
|
||||
|
||||
fn gl(&self) -> Rc<dyn gl::Gl> {
|
||||
debug!("WindowMethods::gl");
|
||||
self.gl.clone()
|
||||
fn webrender_surfman(&self) -> WebrenderSurfman {
|
||||
self.webrender_surfman.clone()
|
||||
}
|
||||
|
||||
fn set_animation_state(&self, state: AnimationState) {
|
||||
|
|
|
@ -18,6 +18,7 @@ log = "0.4"
|
|||
lazy_static = "1"
|
||||
env_logger = "0.7"
|
||||
backtrace = "0.3"
|
||||
surfman = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
libc = "0.2"
|
||||
|
|
|
@ -201,8 +201,6 @@ where
|
|||
/// Callback used by Servo internals
|
||||
#[repr(C)]
|
||||
pub struct CHostCallbacks {
|
||||
pub flush: extern "C" fn(),
|
||||
pub make_current: extern "C" fn(),
|
||||
pub on_load_started: extern "C" fn(),
|
||||
pub on_load_ended: extern "C" fn(),
|
||||
pub on_title_changed: extern "C" fn(title: *const c_char),
|
||||
|
@ -244,6 +242,7 @@ pub struct CInitOptions {
|
|||
pub enable_subpixel_text_antialiasing: bool,
|
||||
pub vslogger_mod_list: *const *const c_char,
|
||||
pub vslogger_mod_size: u32,
|
||||
pub native_widget: *mut c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -442,6 +441,7 @@ unsafe fn init(
|
|||
enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing,
|
||||
gl_context_pointer: gl_context,
|
||||
native_display_pointer: display,
|
||||
native_widget: opts.native_widget,
|
||||
};
|
||||
|
||||
let wakeup = Box::new(WakeupCallback::new(wakeup));
|
||||
|
@ -750,16 +750,6 @@ impl HostCallbacks {
|
|||
}
|
||||
|
||||
impl HostTrait for HostCallbacks {
|
||||
fn flush(&self) {
|
||||
debug!("flush");
|
||||
(self.0.flush)();
|
||||
}
|
||||
|
||||
fn make_current(&self) {
|
||||
debug!("make_current");
|
||||
(self.0.make_current)();
|
||||
}
|
||||
|
||||
fn on_load_started(&self) {
|
||||
debug!("on_load_started");
|
||||
(self.0.on_load_started)();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue