mirror of
https://github.com/Drop-OSS/wry-cef.git
synced 2026-01-30 20:55:24 +01:00
Rework to single thread
This commit is contained in:
@@ -55,6 +55,7 @@ servo-media = { git = "https://github.com/servo/media" }
|
||||
crossbeam-channel = "0.5"
|
||||
getopts = "0.2.17"
|
||||
surfman = { version = "0.8", features = ["chains", "sm-angle", "sm-angle-default", "sm-x11", "sm-raw-window-handle"] }
|
||||
winit = { version = "0.29", features = ["rwh_05"] }
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
||||
javascriptcore-rs = { version = "=1.1", features = ["v2_28"], optional = true }
|
||||
@@ -114,7 +115,6 @@ http-range = "0.1.5"
|
||||
pollster = "0.3.0"
|
||||
# tao = { git = "https://github.com/tauri-apps/tao", default-features = false, features = ["rwh_05"] }
|
||||
wgpu = "0.18.0"
|
||||
winit = { version = "0.29", features = ["rwh_05"] }
|
||||
|
||||
[patch.crates-io]
|
||||
bindgen = { git = "https://github.com/sagudev/rust-bindgen", branch = "f16" }
|
||||
|
||||
@@ -8,7 +8,7 @@ use winit::{
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
};
|
||||
use wry::WebViewBuilder;
|
||||
use wry::{WebViewBuilder, WebViewBuilderExtServo};
|
||||
|
||||
fn main() -> wry::Result<()> {
|
||||
// #[cfg(any(
|
||||
@@ -41,7 +41,7 @@ fn main() -> wry::Result<()> {
|
||||
.unwrap();
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut builder = WebViewBuilder::new(&window);
|
||||
let mut builder = WebViewBuilder::new_servo(window, event_loop.create_proxy());
|
||||
let _webview = builder.with_url("https://tauri.app")?.build()?;
|
||||
|
||||
event_loop
|
||||
|
||||
30
src/lib.rs
30
src/lib.rs
@@ -192,13 +192,18 @@ pub mod prelude {
|
||||
pub use android::JniHandle;
|
||||
#[cfg(target_os = "android")]
|
||||
use android::*;
|
||||
use winit::event_loop::EventLoopProxy;
|
||||
|
||||
#[cfg(servo)]
|
||||
pub(crate) mod servo;
|
||||
#[cfg(gtk)]
|
||||
pub(crate) mod webkitgtk;
|
||||
#[cfg(servo)]
|
||||
pub use crate::servo::WebViewBuilderExtServo;
|
||||
#[cfg(servo)]
|
||||
use crate::servo::*;
|
||||
#[cfg(servo)]
|
||||
use winit::window::Window;
|
||||
#[cfg(gtk)]
|
||||
pub(crate) mod webkitgtk;
|
||||
/// Re-exported [raw-window-handle](https://docs.rs/raw-window-handle/latest/raw_window_handle/) crate.
|
||||
pub use raw_window_handle;
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
@@ -517,6 +522,8 @@ pub struct WebViewBuilder<'a> {
|
||||
web_context: Option<&'a mut WebContext>,
|
||||
#[cfg(gtk)]
|
||||
gtk_widget: Option<&'a gtk::Container>,
|
||||
#[cfg(servo)]
|
||||
winit: Option<(Window, EventLoopProxy<()>)>,
|
||||
}
|
||||
|
||||
impl<'a> WebViewBuilder<'a> {
|
||||
@@ -546,6 +553,8 @@ impl<'a> WebViewBuilder<'a> {
|
||||
web_context: None,
|
||||
#[cfg(gtk)]
|
||||
gtk_widget: None,
|
||||
#[cfg(servo)]
|
||||
winit: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,6 +587,8 @@ impl<'a> WebViewBuilder<'a> {
|
||||
web_context: None,
|
||||
#[cfg(gtk)]
|
||||
gtk_widget: None,
|
||||
#[cfg(servo)]
|
||||
winit: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,7 +977,20 @@ impl<'a> WebViewBuilder<'a> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[cfg(not(gtk))]
|
||||
#[cfg(servo)]
|
||||
if let Some(window) = self.winit {
|
||||
InnerWebView::new_servo(
|
||||
window.0,
|
||||
window.1,
|
||||
self.attrs,
|
||||
self.platform_specific,
|
||||
self.web_context,
|
||||
)?
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[cfg(not(any(gtk, servo)))]
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
use std::{
|
||||
rc::Rc,
|
||||
thread::{self, JoinHandle},
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||
use once_cell::sync::Lazy;
|
||||
use raw_window_handle::RawWindowHandle;
|
||||
use servo::{
|
||||
compositing::windowing::{EmbedderEvent, EmbedderMethods},
|
||||
embedder_traits::{EmbedderMsg, EventLoopWaker},
|
||||
@@ -13,141 +7,90 @@ use servo::{
|
||||
servo_url::ServoUrl,
|
||||
Servo,
|
||||
};
|
||||
use winit::event_loop::EventLoopProxy;
|
||||
|
||||
use crate::Rect;
|
||||
|
||||
use super::window::WebView;
|
||||
|
||||
/// Servo embedder thread. See [`Embedder`] static for more information.
|
||||
pub static SERVO: Lazy<Embedder> = Lazy::new(|| {
|
||||
let (embedder_tx, embedder_rx) = unbounded();
|
||||
let callback_tx = embedder_tx.clone();
|
||||
let _thread = thread::spawn(move || {
|
||||
let mut servo = ServoThread::default();
|
||||
while let Ok(event) = embedder_rx.recv() {
|
||||
if servo.servo.is_none() {
|
||||
servo.init(event, callback_tx.clone());
|
||||
} else {
|
||||
servo.handle_embedder_event(event);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Embedder {
|
||||
_thread,
|
||||
embedder_tx,
|
||||
}
|
||||
});
|
||||
|
||||
#[derive(Default)]
|
||||
struct ServoThread {
|
||||
servo: Option<Servo<WebView>>,
|
||||
webview: Option<(TopLevelBrowsingContextId, Rc<WebView>)>,
|
||||
}
|
||||
|
||||
impl ServoThread {
|
||||
fn init(&mut self, event: ServoEvent, callback: Sender<ServoEvent>) {
|
||||
if let ServoEvent::NewWebView(webview) = event {
|
||||
let webview = Rc::new(WebView::new(webview));
|
||||
let mut init_servo = Servo::new(
|
||||
Box::new(EmbedderWaker(callback)),
|
||||
webview.clone(),
|
||||
Some(String::from(
|
||||
"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0",
|
||||
)),
|
||||
);
|
||||
|
||||
init_servo
|
||||
.servo
|
||||
.handle_events(vec![EmbedderEvent::NewBrowser(
|
||||
ServoUrl::parse("https://servo.org").unwrap(),
|
||||
init_servo.browser_id,
|
||||
)]);
|
||||
init_servo.servo.setup_logging();
|
||||
self.servo.replace(init_servo.servo);
|
||||
self.webview.replace((init_servo.browser_id, webview));
|
||||
} else {
|
||||
log::warn!("Servo embedder received event while servo hasn't initialized yet: {event:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle embedder event from embedder channel. These events are came from users and servo instance.
|
||||
fn handle_embedder_event(&mut self, event: ServoEvent) {
|
||||
log::trace!("Servo embedder is handling event: {event:?}");
|
||||
match event {
|
||||
ServoEvent::NewWebView(_) => {
|
||||
log::warn!("Servo embedder got new webview request while servo is already initialized. Servo hasn't support multiwebview yet.");
|
||||
}
|
||||
ServoEvent::ResizeWebView(rect) => {
|
||||
if let Some((_, webview)) = &self.webview {
|
||||
webview.set_bounds(rect);
|
||||
self.servo().handle_events(vec![EmbedderEvent::Resize]);
|
||||
}
|
||||
}
|
||||
ServoEvent::Wake => {
|
||||
self.handle_servo_message();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_servo_message(&mut self) {
|
||||
let servo = self.servo();
|
||||
let mut embedder_events = vec![];
|
||||
servo.get_events().into_iter().for_each(|(w, m)| {
|
||||
log::trace!("Servo embedder is handling servo message: {m:?} with browser id: {w:?}");
|
||||
match m {
|
||||
EmbedderMsg::BrowserCreated(w) => {
|
||||
embedder_events.push(EmbedderEvent::SelectBrowser(w));
|
||||
}
|
||||
EmbedderMsg::ReadyToPresent => {
|
||||
servo.recomposite();
|
||||
servo.present();
|
||||
}
|
||||
e => {
|
||||
log::warn!("Servo embedder hasn't supported handling this message yet: {e:?}")
|
||||
}
|
||||
}
|
||||
});
|
||||
embedder_events.push(EmbedderEvent::Idle);
|
||||
let need_resize = servo.handle_events(embedder_events);
|
||||
}
|
||||
|
||||
fn servo(&mut self) -> &mut Servo<WebView> {
|
||||
self.servo.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ServoEvent {
|
||||
NewWebView(RawWindowHandle), //TODO url, useragent
|
||||
ResizeWebView(Rect),
|
||||
Wake,
|
||||
}
|
||||
|
||||
unsafe impl Send for ServoEvent {}
|
||||
unsafe impl Sync for ServoEvent {}
|
||||
|
||||
/// Servo embedder is an instance to work with other webview types and threads.
|
||||
/// This creates its own event loop in another thread and using crossbean channel to communicate.
|
||||
pub struct Embedder {
|
||||
_thread: JoinHandle<()>,
|
||||
embedder_tx: Sender<ServoEvent>,
|
||||
servo: Servo<WebView>,
|
||||
webview: (TopLevelBrowsingContextId, Rc<WebView>),
|
||||
}
|
||||
|
||||
impl Embedder {
|
||||
/// The sender to send event for servo thread to handle.
|
||||
pub fn sender(&self) -> Sender<ServoEvent> {
|
||||
self.embedder_tx.clone()
|
||||
pub fn new(webview: WebView, callback: EmbedderWaker) -> Self {
|
||||
let webview = Rc::new(webview);
|
||||
let mut init_servo = Servo::new(
|
||||
Box::new(callback),
|
||||
webview.clone(),
|
||||
Some(String::from(
|
||||
"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0",
|
||||
)),
|
||||
);
|
||||
|
||||
init_servo
|
||||
.servo
|
||||
.handle_events(vec![EmbedderEvent::NewBrowser(
|
||||
ServoUrl::parse("https://servo.org").unwrap(),
|
||||
init_servo.browser_id,
|
||||
)]);
|
||||
init_servo.servo.setup_logging();
|
||||
Embedder {
|
||||
servo: init_servo.servo,
|
||||
webview: (init_servo.browser_id, webview),
|
||||
}
|
||||
}
|
||||
|
||||
// /// The receiver to get event from servo thread.
|
||||
// pub fn receiver(&self) -> Receiver<ServoEvent> {
|
||||
// self.user_rx.clone()
|
||||
// /// Handle embedder event from embedder channel. These events are came from users and servo instance.
|
||||
// fn handle_embedder_event(&mut self, event: ServoEvent) {
|
||||
// log::trace!("Servo embedder is handling event: {event:?}");
|
||||
// match event {
|
||||
// ServoEvent::NewWebView(_) => {
|
||||
// log::warn!("Servo embedder got new webview request while servo is already initialized. Servo hasn't support multiwebview yet.");
|
||||
// }
|
||||
// ServoEvent::ResizeWebView(rect) => {
|
||||
// self.webview.1.set_bounds(rect);
|
||||
// self.servo.handle_events(vec![EmbedderEvent::Resize]);
|
||||
// }
|
||||
// ServoEvent::Wake => {
|
||||
// self.handle_servo_message();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn handle_servo_message(&mut self) {
|
||||
// let mut embedder_events = vec![];
|
||||
// let mut need_present = false;
|
||||
// self.servo.get_events().into_iter().for_each(|(w, m)| {
|
||||
// log::trace!("Servo embedder is handling servo message: {m:?} with browser id: {w:?}");
|
||||
// match m {
|
||||
// EmbedderMsg::BrowserCreated(w) => {
|
||||
// embedder_events.push(EmbedderEvent::SelectBrowser(w));
|
||||
// embedder_events.push(EmbedderEvent::Idle);
|
||||
// }
|
||||
// // EmbedderMsg::ResizeTo(_) |
|
||||
// EmbedderMsg::ReadyToPresent => {
|
||||
// need_present = true;
|
||||
// }
|
||||
// e => {
|
||||
// log::warn!("Servo embedder hasn't supported handling this message yet: {e:?}")
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// let need_resize = self.servo.handle_events(embedder_events);
|
||||
// // if need_resize {
|
||||
// // servo.repaint_synchronously();
|
||||
// // servo.present();
|
||||
// if need_present {
|
||||
// self.servo.recomposite();
|
||||
// self.servo.present();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EmbedderWaker(pub Sender<ServoEvent>);
|
||||
pub struct EmbedderWaker(pub EventLoopProxy<()>);
|
||||
|
||||
impl EmbedderMethods for EmbedderWaker {
|
||||
fn create_event_loop_waker(&mut self) -> Box<dyn EventLoopWaker> {
|
||||
@@ -161,8 +104,8 @@ impl EventLoopWaker for EmbedderWaker {
|
||||
}
|
||||
|
||||
fn wake(&self) {
|
||||
if let Err(e) = self.0.send(ServoEvent::Wake) {
|
||||
log::error!("Failed to send wake up event to servo thread: {}", e);
|
||||
if let Err(e) = self.0.send_event(()) {
|
||||
log::error!("Failed to send wake up event to servo embedder: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use crossbeam_channel::Sender;
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
use url::Url;
|
||||
use winit::{event_loop::EventLoopProxy, window::Window};
|
||||
|
||||
use crate::{Rect, Result, WebContext, WebViewAttributes, RGBA};
|
||||
use crate::{Rect, Result, WebContext, WebViewAttributes, WebViewBuilder, RGBA};
|
||||
|
||||
use self::embedder::{ServoEvent, SERVO};
|
||||
use self::{
|
||||
embedder::{Embedder, EmbedderWaker},
|
||||
window::WebView,
|
||||
};
|
||||
|
||||
mod embedder;
|
||||
mod prefs;
|
||||
@@ -12,12 +15,13 @@ mod resources;
|
||||
mod window;
|
||||
|
||||
pub(crate) struct InnerWebView {
|
||||
embedder_tx: Sender<ServoEvent>,
|
||||
servo: Embedder,
|
||||
}
|
||||
|
||||
impl InnerWebView {
|
||||
pub fn new<W: HasRawWindowHandle>(
|
||||
window: &W,
|
||||
pub fn new_servo(
|
||||
window: Window,
|
||||
proxy: EventLoopProxy<()>,
|
||||
attributes: WebViewAttributes,
|
||||
pl_attrs: super::PlatformSpecificWebViewAttributes,
|
||||
web_context: Option<&mut WebContext>,
|
||||
@@ -25,21 +29,28 @@ impl InnerWebView {
|
||||
resources::init(web_context);
|
||||
prefs::init();
|
||||
|
||||
let embedder_tx = SERVO.sender();
|
||||
embedder_tx
|
||||
.send(ServoEvent::NewWebView(window.raw_window_handle()))
|
||||
.expect("Fail to send event to Servo thread.");
|
||||
let webview = WebView::new(window);
|
||||
let callback = EmbedderWaker(proxy);
|
||||
let servo = Embedder::new(webview, callback);
|
||||
|
||||
Ok(Self { embedder_tx })
|
||||
Ok(Self { servo })
|
||||
}
|
||||
|
||||
pub fn new<W: HasRawWindowHandle>(
|
||||
_window: &W,
|
||||
_attributes: WebViewAttributes,
|
||||
_pl_attrs: super::PlatformSpecificWebViewAttributes,
|
||||
_web_context: Option<&mut WebContext>,
|
||||
) -> Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn new_as_child<W: HasRawWindowHandle>(
|
||||
parent: &W,
|
||||
attributes: WebViewAttributes,
|
||||
pl_attrs: super::PlatformSpecificWebViewAttributes,
|
||||
web_context: Option<&mut WebContext>,
|
||||
_parent: &W,
|
||||
_attributes: WebViewAttributes,
|
||||
_pl_attrs: super::PlatformSpecificWebViewAttributes,
|
||||
_web_context: Option<&mut WebContext>,
|
||||
) -> Result<Self> {
|
||||
// Ok(Self)
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -57,10 +68,6 @@ impl InnerWebView {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(&self, js: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(debug_assertions, feature = "devtools"))]
|
||||
pub fn open_devtools(&self) {}
|
||||
|
||||
@@ -86,21 +93,31 @@ impl InnerWebView {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_bounds(&self, bounds: Rect) {
|
||||
self.handle(ServoEvent::ResizeWebView(bounds));
|
||||
}
|
||||
pub fn set_bounds(&self, bounds: Rect) {}
|
||||
|
||||
pub fn set_visible(&self, visible: bool) {}
|
||||
|
||||
pub fn focus(&self) {}
|
||||
|
||||
pub fn handle(&self, event: ServoEvent) {
|
||||
if let Err(e) = self.embedder_tx.send(event) {
|
||||
log::error!("Failed to send servo event to servo thread: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn platform_webview_version() -> Result<String> {
|
||||
Ok(String::from(""))
|
||||
}
|
||||
|
||||
pub trait WebViewBuilderExtServo {
|
||||
fn new_servo(window: Window, proxy: EventLoopProxy<()>) -> Self;
|
||||
}
|
||||
|
||||
impl WebViewBuilderExtServo for WebViewBuilder<'_> {
|
||||
fn new_servo(window: Window, proxy: EventLoopProxy<()>) -> Self {
|
||||
Self {
|
||||
attrs: WebViewAttributes::default(),
|
||||
window: None,
|
||||
as_child: false,
|
||||
#[allow(clippy::default_constructed_unit_structs)]
|
||||
platform_specific: super::PlatformSpecificWebViewAttributes::default(),
|
||||
web_context: None,
|
||||
winit: Some((window, proxy)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::Rect;
|
||||
use std::cell::Cell;
|
||||
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
use raw_window_handle::{HasRawWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||
use servo::{
|
||||
compositing::windowing::{AnimationState, EmbedderCoordinates, WindowMethods},
|
||||
config::pref,
|
||||
@@ -12,46 +11,35 @@ use servo::{
|
||||
use surfman::{Connection, GLApi, GLVersion, SurfaceType};
|
||||
// FIXME servo should re-export this.
|
||||
use servo_media::player::context::{GlApi, GlContext, NativeDisplay};
|
||||
use winit::window::Window;
|
||||
|
||||
/// This is the type for servo embedder. Not for public usage.
|
||||
pub struct WebView {
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
animation_state: Cell<AnimationState>,
|
||||
rect: Cell<Rect>, //TODO hidpi
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl WebView {
|
||||
pub fn new(window_handle: RawWindowHandle) -> Self {
|
||||
pub fn new(window: Window) -> Self {
|
||||
let connection = Connection::new().expect("Failed to create surfman connection");
|
||||
let adapter = connection
|
||||
.create_adapter()
|
||||
.expect("Failed to create surfman adapter");
|
||||
let native_widget = connection
|
||||
.create_native_widget_from_rwh(window_handle)
|
||||
.create_native_widget_from_rwh(window.raw_window_handle())
|
||||
.expect("Failed to create surfman native widget");
|
||||
let surface_type = SurfaceType::Widget { native_widget };
|
||||
let webrender_surfman = WebrenderSurfman::create(&connection, &adapter, surface_type)
|
||||
.expect("Failed to create webrender surfman");
|
||||
log::trace!("Created webrender surfman for window {:?}", window_handle);
|
||||
log::trace!("Created webrender surfman for window {:?}", window);
|
||||
|
||||
Self {
|
||||
webrender_surfman,
|
||||
animation_state: Cell::new(AnimationState::Idle),
|
||||
rect: Cell::new(Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
}),
|
||||
window,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_bounds(&self, rect: Rect) {
|
||||
self.rect.replace(rect);
|
||||
let _ = self
|
||||
.webrender_surfman
|
||||
.resize(Size2D::new(rect.width as i32, rect.height as i32));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for WebView {}
|
||||
@@ -59,16 +47,19 @@ unsafe impl Sync for WebView {}
|
||||
|
||||
impl WindowMethods for WebView {
|
||||
fn get_coordinates(&self) -> EmbedderCoordinates {
|
||||
let rect = self.rect.get();
|
||||
let pos = Point2D::new(rect.x, rect.y);
|
||||
let size = Size2D::new(rect.width as i32, rect.height as i32);
|
||||
let size = self.window.inner_size();
|
||||
let pos = Point2D::new(0, 0);
|
||||
let viewport = Size2D::new(size.width as i32, size.height as i32);
|
||||
|
||||
let size = self.window.current_monitor().unwrap().size();
|
||||
let screen = Size2D::new(size.width as i32, size.height as i32);
|
||||
EmbedderCoordinates {
|
||||
hidpi_factor: Scale::new(1.0),
|
||||
screen: Size2D::new(3840, 2160),
|
||||
screen_avail: Size2D::new(3840, 2160),
|
||||
window: (size, pos),
|
||||
framebuffer: size,
|
||||
viewport: DeviceIntRect::new(pos, size),
|
||||
hidpi_factor: Scale::new(self.window.scale_factor() as f32),
|
||||
screen,
|
||||
screen_avail: screen,
|
||||
window: (viewport, pos),
|
||||
framebuffer: viewport,
|
||||
viewport: DeviceIntRect::new(pos, viewport),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user