Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add verso protocol #202

Merged
merged 2 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ fonts = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
layout_thread_2020 = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
media = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
net = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
net_traits = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
profile = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
profile_traits = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
script = { git = "https://github.com/servo/servo.git", rev = "fc0835b" }
Expand All @@ -104,6 +105,7 @@ cargo-packager-resource-resolver = { version = "0.1.1", features = [
"auto-detect-format",
], optional = true }
url = "2.5.2"
headers = "0.3"
versoview_messages = { path = "./versoview_messages" }

[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
Expand Down
16 changes: 8 additions & 8 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use webrender_api::{
};
use webrender_traits::display_list::{HitTestInfo, ScrollTree};
use webrender_traits::{
CompositorHitTestResult, CrossProcessCompositorMessage, ImageUpdate, UntrustedNodeAddress
CompositorHitTestResult, CrossProcessCompositorMessage, ImageUpdate, UntrustedNodeAddress,
};
use winit::window::WindowId;

Expand Down Expand Up @@ -572,7 +572,7 @@ impl IOCompositor {

CompositorMsg::CrossProcess(cross_proces_message) => {
self.handle_cross_process_message(cross_proces_message);
},
}
}

true
Expand Down Expand Up @@ -707,11 +707,11 @@ impl IOCompositor {
match update {
ImageUpdate::AddImage(key, desc, data) => {
txn.add_image(key, desc, data.into(), None)
},
}
ImageUpdate::DeleteImage(key) => txn.delete_image(key),
ImageUpdate::UpdateImage(key, desc, data) => {
txn.update_image(key, desc, data.into(), &DirtyRect::All)
},
}
}
}
self.webrender_api
Expand All @@ -727,7 +727,7 @@ impl IOCompositor {
transaction.add_native_font(font_key, native_handle);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
},
}

CrossProcessCompositorMessage::AddFontInstance(
font_instance_key,
Expand Down Expand Up @@ -777,13 +777,13 @@ impl IOCompositor {
if let Err(e) = req.send(self.viewport.into()) {
warn!("Sending response to get client window failed ({:?}).", e);
}
},
}

CrossProcessCompositorMessage::GetScreenSize(req) => {
if let Err(e) = req.send(self.viewport) {
warn!("Sending response to get screen size failed ({:?}).", e);
}
},
}

CrossProcessCompositorMessage::GetAvailableScreenSize(req) => {
if let Err(e) = req.send(self.viewport) {
Expand Down Expand Up @@ -833,7 +833,7 @@ impl IOCompositor {
.map(|_| self.webrender_api.generate_font_instance_key())
.collect();
let _ = result_sender.send((font_keys, font_instance_keys));
},
}
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetClientWindowRect(
req,
)) => {
Expand Down
45 changes: 45 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use std::{fs, path::PathBuf};

use embedder_traits::resources::{self, Resource, ResourceReaderMethods};
use headers::{ContentType, HeaderMapExt};
use net::protocols::{ProtocolHandler, ProtocolRegistry};
use net_traits::{
request::Request,
response::{Response, ResponseBody},
ResourceFetchTiming,
};
use servo_config::opts::{default_opts, set_options, Opts};

/// Configuration of Verso instance.
Expand All @@ -20,6 +27,14 @@ impl Config {
Self { opts, resource_dir }
}

/// Register URL scheme protocols
pub fn create_protocols(&self) -> ProtocolRegistry {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called register_protocols instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, this is to create the protocols

let handler = ResourceReader(self.resource_dir.clone());
let mut protocols = ProtocolRegistry::with_internal_protocols();
protocols.register("verso", handler);
protocols
}

/// Init options and preferences.
pub fn init(self) {
// Set the resource files and preferences of Servo.
Expand All @@ -46,3 +61,33 @@ impl ResourceReaderMethods for ResourceReader {
vec![]
}
}

impl ProtocolHandler for ResourceReader {
fn load(
&self,
request: &mut Request,
_done_chan: &mut net::fetch::methods::DoneChannel,
_context: &net::fetch::methods::FetchContext,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Response> + Send>> {
let path = self.0.join(request.current_url().domain().unwrap());

let response = if let Ok(file) = fs::read(path) {
let mut response = Response::new(
request.current_url(),
ResourceFetchTiming::new(request.timing_type()),
);

// Set Content-Type header.
// TODO: We assume it's HTML for now. This should be updated once we have IPC interface.
response.headers.typed_insert(ContentType::html());

*response.body.lock().unwrap() = ResponseBody::Done(file);

response
} else {
Response::network_internal_error("Opening file failed")
};

Box::pin(std::future::ready(response))
}
}
28 changes: 10 additions & 18 deletions src/verso.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
use std::{
borrow::Cow,
collections::HashMap,
path::PathBuf,
sync::{atomic::Ordering, Arc},
};

use arboard::Clipboard;
use base::id::WebViewId;
use base::id::{PipelineNamespace, PipelineNamespaceId, WebViewId};
use bluetooth::BluetoothThreadFactory;
use bluetooth_traits::BluetoothRequest;
use canvas::canvas_paint_thread::CanvasPaintThread;
use compositing_traits::{
CompositorMsg, CompositorProxy, CompositorReceiver, ConstellationMsg,
};
use compositing_traits::{CompositorMsg, CompositorProxy, CompositorReceiver, ConstellationMsg};
use constellation::{Constellation, FromCompositorLogger, InitialConstellationState};
use crossbeam_channel::{unbounded, Sender};
use devtools;
Expand All @@ -24,7 +21,7 @@ use ipc_channel::router::ROUTER;
use layout_thread_2020;
use log::{Log, Metadata, Record};
use media::{GlApi, GlContext, NativeDisplay, WindowGLContext};
use net::{protocols::ProtocolRegistry, resource_thread};
use net::resource_thread;
use profile;
use script::{self, JSEngineSetup};
use script_traits::WindowSizeData;
Expand Down Expand Up @@ -62,7 +59,6 @@ pub struct Verso {
_js_engine_setup: Option<JSEngineSetup>,
/// FIXME: It's None on wayland in Flatpak. Find a way to support this.
clipboard: Option<Clipboard>,
resource_dir: PathBuf,
}

impl Verso {
Expand All @@ -84,8 +80,10 @@ impl Verso {
/// - Image Cache: Enabled
pub fn new(evl: &ActiveEventLoop, proxy: EventLoopProxy<()>, config: Config) -> Self {
// Initialize configurations and Verso window
let resource_dir = config.resource_dir.clone();
let protocols = config.create_protocols();
config.init();
// Reserving a namespace to create TopLevelBrowsingContextId.
PipelineNamespace::install(PipelineNamespaceId(0));
let (window, rendering_context) = Window::new(evl);
let event_loop_waker = Box::new(Waker(proxy));
let opts = opts::get();
Expand Down Expand Up @@ -262,9 +260,6 @@ impl Verso {
let bluetooth_thread: IpcSender<BluetoothRequest> =
BluetoothThreadFactory::new(embedder_sender.clone());

// Register URL scheme protocols
let protocols = ProtocolRegistry::with_internal_protocols();

// Create resource thread pool
let user_agent: Cow<'static, str> = default_user_agent_string().into();
let (public_resource_threads, private_resource_threads) =
Expand All @@ -282,7 +277,8 @@ impl Verso {

// Create font cache thread
let system_font_service = Arc::new(
SystemFontService::spawn(compositor_sender.cross_process_compositor_api.clone()).to_proxy(),
SystemFontService::spawn(compositor_sender.cross_process_compositor_api.clone())
.to_proxy(),
);

// Create canvas thread
Expand Down Expand Up @@ -369,8 +365,7 @@ impl Verso {
// Send the constellation message to start Panel UI
// TODO: Should become a window method
let panel_id = window.panel.as_ref().unwrap().webview_id;
let path = resource_dir.join("panel.html");
let url = ServoUrl::from_file_path(path.to_str().unwrap()).unwrap();
let url = ServoUrl::parse("verso://panel.html").unwrap();
send_to_constellation(
&constellation_sender,
ConstellationMsg::NewWebView(url, panel_id),
Expand All @@ -387,7 +382,6 @@ impl Verso {
embedder_receiver,
_js_engine_setup: js_engine_setup,
clipboard: Clipboard::new().ok(),
resource_dir,
};

verso.setup_logging();
Expand Down Expand Up @@ -445,10 +439,8 @@ impl Verso {
let mut window =
Window::new_with_compositor(evl, compositor);
let panel_id = WebViewId::new();
let path = self.resource_dir.join("panel.html");
let url =
ServoUrl::from_file_path(path.to_str().unwrap())
.unwrap();
ServoUrl::parse("verso://panel.html").unwrap();
send_to_constellation(
&self.constellation_sender,
ConstellationMsg::NewWebView(url, panel_id),
Expand Down
23 changes: 1 addition & 22 deletions src/webview.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use arboard::Clipboard;
use base::id::{BrowsingContextId, PipelineNamespace, PipelineNamespaceId, WebViewId};
use base::id::{BrowsingContextId, WebViewId};
use compositing_traits::ConstellationMsg;
use crossbeam_channel::Sender;
use embedder_traits::{CompositorEventVariant, EmbedderMsg, PromptDefinition};
Expand Down Expand Up @@ -29,27 +29,6 @@ impl WebView {
Self { webview_id, rect }
}

/// Create a panel view from Winit window. A panel is a special web view that focus on controlling states around window.
/// It could be treated as the control panel or navigation bar of the window depending on usages.
///
/// At the moment, following Web API is supported:
/// - Close window: `window.close()`
/// - Navigate to previous page: `window.prompt('PREV')`
/// - Navigate to next page: `window.prompt('FORWARD')`
/// - Refresh the page: `window.prompt('REFRESH')`
/// - Minimize the window: `window.prompt('MINIMIZE')`
/// - Maximize the window: `window.prompt('MAXIMIZE')`
/// - Navigate to a specific URL: `window.prompt('NAVIGATE_TO:${url}')`
pub fn new_panel(rect: DeviceIntRect) -> Self {
// Reserving a namespace to create TopLevelBrowsingContextId.
PipelineNamespace::install(PipelineNamespaceId(0));
let id = WebViewId::new();
Self {
webview_id: id,
rect,
}
}

/// Set the webview size corresponding to the window size.
pub fn set_size(&mut self, mut rect: DeviceIntRect) {
rect.min.y = rect.max.y.min(100);
Expand Down
17 changes: 15 additions & 2 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,17 @@ pub struct Window {
pub(crate) window: WinitWindow,
/// GL surface of the window
pub(crate) surface: Surface<WindowSurface>,
/// The main control panel of this window.
/// The main panel of this window. A panel is a special web view that focus on controlling states around window.
/// It could be treated as the control panel or navigation bar of the window depending on usages.
///
/// At the moment, following Web API is supported:
/// - Close window: `window.close()`
/// - Navigate to previous page: `window.prompt('PREV')`
/// - Navigate to next page: `window.prompt('FORWARD')`
/// - Refresh the page: `window.prompt('REFRESH')`
/// - Minimize the window: `window.prompt('MINIMIZE')`
/// - Maximize the window: `window.prompt('MAXIMIZE')`
/// - Navigate to a specific URL: `window.prompt('NAVIGATE_TO:${url}')`
pub(crate) panel: Option<WebView>,
/// The WebView of this window.
pub(crate) webview: Option<WebView>,
Expand Down Expand Up @@ -89,7 +99,10 @@ impl Window {
Self {
window,
surface,
panel: Some(WebView::new_panel(DeviceIntRect::from_size(size))),
panel: Some(WebView::new(
WebViewId::new(),
DeviceIntRect::from_size(size),
)),
webview: None,
mouse_position: Cell::new(PhysicalPosition::default()),
modifiers_state: Cell::new(ModifiersState::default()),
Expand Down
1 change: 1 addition & 0 deletions versoview/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions versoview_messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@