mirror of
https://github.com/servo/servo.git
synced 2025-07-03 13:33:39 +01:00
Auto merge of #20228 - paulrouget:ports_refactor, r=jdm
Ports refactoring Depends on https://github.com/servo/servo/pull/20071 and https://github.com/servo/servo/pull/19895 This PR does 3 things: 1) merge all the embedder coordinates callbacks into one 2) hand the embedder messages directly to the embedder 3) split the embedder code in 2 files: window.rs and browser.rs This is in preparation for tabs support in `ports/`. We want to separate the windowing logic (glutin stuff) and the browsing logic (tabs management, browsers state, etc). It's also easier to bypass the callbacks and directly handle events. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- 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. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20228) <!-- Reviewable:end -->
This commit is contained in:
commit
2de89377db
14 changed files with 1019 additions and 1048 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2698,14 +2698,12 @@ dependencies = [
|
||||||
"libservo 0.0.1",
|
"libservo 0.0.1",
|
||||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
"net_traits 0.0.1",
|
|
||||||
"osmesa-src 17.3.1-devel (git+https://github.com/servo/osmesa-src)",
|
"osmesa-src 17.3.1-devel (git+https://github.com/servo/osmesa-src)",
|
||||||
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"script_traits 0.0.1",
|
"script_traits 0.0.1",
|
||||||
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"servo_config 0.0.1",
|
"servo_config 0.0.1",
|
||||||
"servo_geometry 0.0.1",
|
"servo_geometry 0.0.1",
|
||||||
"servo_url 0.0.1",
|
|
||||||
"sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style_traits 0.0.1",
|
"style_traits 0.0.1",
|
||||||
"tinyfiledialogs 3.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tinyfiledialogs 3.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -34,9 +34,9 @@ use style_traits::viewport::ViewportConstraints;
|
||||||
use time::{now, precise_time_ns, precise_time_s};
|
use time::{now, precise_time_ns, precise_time_s};
|
||||||
use touch::{TouchHandler, TouchAction};
|
use touch::{TouchHandler, TouchAction};
|
||||||
use webrender;
|
use webrender;
|
||||||
use webrender_api::{self, DeviceIntPoint, DevicePoint, DeviceUintRect, DeviceUintSize, HitTestFlags, HitTestResult};
|
use webrender_api::{self, DeviceIntPoint, DevicePoint, HitTestFlags, HitTestResult};
|
||||||
use webrender_api::{LayoutVector2D, ScrollEventPhase, ScrollLocation};
|
use webrender_api::{LayoutVector2D, ScrollEventPhase, ScrollLocation};
|
||||||
use windowing::{self, MouseWindowEvent, WebRenderDebugOption, WindowMethods};
|
use windowing::{self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum UnableToComposite {
|
enum UnableToComposite {
|
||||||
|
@ -110,12 +110,6 @@ pub struct IOCompositor<Window: WindowMethods> {
|
||||||
/// The scene scale, to allow for zooming and high-resolution painting.
|
/// The scene scale, to allow for zooming and high-resolution painting.
|
||||||
scale: TypedScale<f32, LayerPixel, DevicePixel>,
|
scale: TypedScale<f32, LayerPixel, DevicePixel>,
|
||||||
|
|
||||||
/// The size of the rendering area.
|
|
||||||
frame_size: DeviceUintSize,
|
|
||||||
|
|
||||||
/// The position and size of the window within the rendering area.
|
|
||||||
window_rect: DeviceUintRect,
|
|
||||||
|
|
||||||
/// "Mobile-style" zoom that does not reflow the page.
|
/// "Mobile-style" zoom that does not reflow the page.
|
||||||
viewport_zoom: PinchZoomFactor,
|
viewport_zoom: PinchZoomFactor,
|
||||||
|
|
||||||
|
@ -126,9 +120,6 @@ pub struct IOCompositor<Window: WindowMethods> {
|
||||||
/// "Desktop-style" zoom that resizes the viewport to fit the window.
|
/// "Desktop-style" zoom that resizes the viewport to fit the window.
|
||||||
page_zoom: TypedScale<f32, CSSPixel, DeviceIndependentPixel>,
|
page_zoom: TypedScale<f32, CSSPixel, DeviceIndependentPixel>,
|
||||||
|
|
||||||
/// The device pixel ratio for this window.
|
|
||||||
scale_factor: TypedScale<f32, DeviceIndependentPixel, DevicePixel>,
|
|
||||||
|
|
||||||
/// The type of composition to perform
|
/// The type of composition to perform
|
||||||
composite_target: CompositeTarget,
|
composite_target: CompositeTarget,
|
||||||
|
|
||||||
|
@ -193,6 +184,9 @@ pub struct IOCompositor<Window: WindowMethods> {
|
||||||
/// these frames, it records the paint time for each of them and sends the
|
/// these frames, it records the paint time for each of them and sends the
|
||||||
/// metric to the corresponding layout thread.
|
/// metric to the corresponding layout thread.
|
||||||
pending_paint_metrics: HashMap<PipelineId, Epoch>,
|
pending_paint_metrics: HashMap<PipelineId, Epoch>,
|
||||||
|
|
||||||
|
/// The coordinates of the native window, its view and the screen.
|
||||||
|
embedder_coordinates: EmbedderCoordinates,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -350,9 +344,6 @@ impl webrender_api::RenderNotifier for RenderNotifier {
|
||||||
impl<Window: WindowMethods> IOCompositor<Window> {
|
impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
fn new(window: Rc<Window>, state: InitialCompositorState)
|
fn new(window: Rc<Window>, state: InitialCompositorState)
|
||||||
-> IOCompositor<Window> {
|
-> IOCompositor<Window> {
|
||||||
let frame_size = window.framebuffer_size();
|
|
||||||
let window_rect = window.window_rect();
|
|
||||||
let scale_factor = window.hidpi_factor();
|
|
||||||
let composite_target = match opts::get().output_file {
|
let composite_target = match opts::get().output_file {
|
||||||
Some(_) => CompositeTarget::PngFile,
|
Some(_) => CompositeTarget::PngFile,
|
||||||
None => CompositeTarget::Window
|
None => CompositeTarget::Window
|
||||||
|
@ -360,14 +351,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
|
|
||||||
IOCompositor {
|
IOCompositor {
|
||||||
gl: window.gl(),
|
gl: window.gl(),
|
||||||
|
embedder_coordinates: window.get_coordinates(),
|
||||||
window: window,
|
window: window,
|
||||||
port: state.receiver,
|
port: state.receiver,
|
||||||
root_pipeline: None,
|
root_pipeline: None,
|
||||||
pipeline_details: HashMap::new(),
|
pipeline_details: HashMap::new(),
|
||||||
frame_size: frame_size,
|
|
||||||
window_rect: window_rect,
|
|
||||||
scale: TypedScale::new(1.0),
|
scale: TypedScale::new(1.0),
|
||||||
scale_factor: scale_factor,
|
|
||||||
composition_request: CompositionRequest::NoCompositingNecessary,
|
composition_request: CompositionRequest::NoCompositingNecessary,
|
||||||
touch_handler: TouchHandler::new(),
|
touch_handler: TouchHandler::new(),
|
||||||
pending_scroll_zoom_events: Vec::new(),
|
pending_scroll_zoom_events: Vec::new(),
|
||||||
|
@ -548,6 +537,24 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.pending_paint_metrics.insert(pipeline_id, epoch);
|
self.pending_paint_metrics.insert(pipeline_id, epoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(Msg::GetClientWindow(req), ShutdownState::NotShuttingDown) => {
|
||||||
|
if let Err(e) = req.send(self.embedder_coordinates.window) {
|
||||||
|
warn!("Sending response to get client window failed ({}).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(Msg::GetScreenSize(req), ShutdownState::NotShuttingDown) => {
|
||||||
|
if let Err(e) = req.send(self.embedder_coordinates.screen) {
|
||||||
|
warn!("Sending response to get screen size failed ({}).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(Msg::GetScreenAvailSize(req), ShutdownState::NotShuttingDown) => {
|
||||||
|
if let Err(e) = req.send(self.embedder_coordinates.screen_avail) {
|
||||||
|
warn!("Sending response to get screen avail size failed ({}).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// When we are shutting_down, we need to avoid performing operations
|
// When we are shutting_down, we need to avoid performing operations
|
||||||
// such as Paint that may crash because we have begun tearing down
|
// such as Paint that may crash because we have begun tearing down
|
||||||
// the rest of our resources.
|
// the rest of our resources.
|
||||||
|
@ -634,14 +641,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_window_size(&self, size_type: WindowSizeType) {
|
fn send_window_size(&self, size_type: WindowSizeType) {
|
||||||
let dppx = self.page_zoom * self.hidpi_factor();
|
let dppx = self.page_zoom * self.embedder_coordinates.hidpi_factor;
|
||||||
|
|
||||||
self.webrender_api.set_window_parameters(self.webrender_document,
|
self.webrender_api.set_window_parameters(self.webrender_document,
|
||||||
self.frame_size,
|
self.embedder_coordinates.framebuffer,
|
||||||
self.window_rect,
|
self.embedder_coordinates.viewport,
|
||||||
self.hidpi_factor().get());
|
self.embedder_coordinates.hidpi_factor.get());
|
||||||
|
|
||||||
let initial_viewport = self.window_rect.size.to_f32() / dppx;
|
let initial_viewport = self.embedder_coordinates.viewport.size.to_f32() / dppx;
|
||||||
|
|
||||||
let data = WindowSizeData {
|
let data = WindowSizeData {
|
||||||
device_pixel_ratio: dppx,
|
device_pixel_ratio: dppx,
|
||||||
|
@ -662,24 +669,19 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
pub fn on_resize_window_event(&mut self) {
|
pub fn on_resize_window_event(&mut self) {
|
||||||
debug!("compositor resize requested");
|
debug!("compositor resize requested");
|
||||||
|
|
||||||
|
let old_coords = self.embedder_coordinates;
|
||||||
|
self.embedder_coordinates = self.window.get_coordinates();
|
||||||
|
|
||||||
// A size change could also mean a resolution change.
|
// A size change could also mean a resolution change.
|
||||||
let new_scale_factor = self.window.hidpi_factor();
|
if self.embedder_coordinates.hidpi_factor != old_coords.hidpi_factor {
|
||||||
if self.scale_factor != new_scale_factor {
|
|
||||||
self.scale_factor = new_scale_factor;
|
|
||||||
self.update_zoom_transform();
|
self.update_zoom_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_window_rect = self.window.window_rect();
|
if self.embedder_coordinates.viewport == old_coords.viewport &&
|
||||||
let new_frame_size = self.window.framebuffer_size();
|
self.embedder_coordinates.framebuffer == old_coords.framebuffer {
|
||||||
|
|
||||||
if self.window_rect == new_window_rect &&
|
|
||||||
self.frame_size == new_frame_size {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.frame_size = new_frame_size;
|
|
||||||
self.window_rect = new_window_rect;
|
|
||||||
|
|
||||||
self.send_window_size(WindowSizeType::Resize);
|
self.send_window_size(WindowSizeType::Resize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,7 +1098,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
Some(device_pixels_per_px) => TypedScale::new(device_pixels_per_px),
|
Some(device_pixels_per_px) => TypedScale::new(device_pixels_per_px),
|
||||||
None => match opts::get().output_file {
|
None => match opts::get().output_file {
|
||||||
Some(_) => TypedScale::new(1.0),
|
Some(_) => TypedScale::new(1.0),
|
||||||
None => self.scale_factor
|
None => self.embedder_coordinates.hidpi_factor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1256,7 +1258,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
fn composite_specific_target(&mut self,
|
fn composite_specific_target(&mut self,
|
||||||
target: CompositeTarget)
|
target: CompositeTarget)
|
||||||
-> Result<Option<Image>, UnableToComposite> {
|
-> Result<Option<Image>, UnableToComposite> {
|
||||||
let (width, height) = (self.frame_size.width_typed(), self.frame_size.height_typed());
|
let width = self.embedder_coordinates.framebuffer.width_typed();
|
||||||
|
let height = self.embedder_coordinates.framebuffer.height_typed();
|
||||||
if !self.window.prepare_for_composite(width, height) {
|
if !self.window.prepare_for_composite(width, height) {
|
||||||
return Err(UnableToComposite::WindowUnprepared)
|
return Err(UnableToComposite::WindowUnprepared)
|
||||||
}
|
}
|
||||||
|
@ -1291,7 +1294,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
|
|
||||||
// Paint the scene.
|
// Paint the scene.
|
||||||
// TODO(gw): Take notice of any errors the renderer returns!
|
// TODO(gw): Take notice of any errors the renderer returns!
|
||||||
self.webrender.render(self.frame_size).ok();
|
self.webrender.render(self.embedder_coordinates.framebuffer).ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there are pending paint metrics, we check if any of the painted epochs is
|
// If there are pending paint metrics, we check if any of the painted epochs is
|
||||||
|
|
|
@ -121,13 +121,6 @@ pub enum EmbedderMsg {
|
||||||
MoveTo(TopLevelBrowsingContextId, DeviceIntPoint),
|
MoveTo(TopLevelBrowsingContextId, DeviceIntPoint),
|
||||||
/// Resize the window to size
|
/// Resize the window to size
|
||||||
ResizeTo(TopLevelBrowsingContextId, DeviceUintSize),
|
ResizeTo(TopLevelBrowsingContextId, DeviceUintSize),
|
||||||
/// Get Window Informations size and position
|
|
||||||
GetClientWindow(TopLevelBrowsingContextId,
|
|
||||||
IpcSender<(DeviceUintSize, DeviceIntPoint)>),
|
|
||||||
/// Get screen size (pixel)
|
|
||||||
GetScreenSize(TopLevelBrowsingContextId, IpcSender<(DeviceUintSize)>),
|
|
||||||
/// Get screen available size (pixel)
|
|
||||||
GetScreenAvailSize(TopLevelBrowsingContextId, IpcSender<(DeviceUintSize)>),
|
|
||||||
/// Wether or not to follow a link
|
/// Wether or not to follow a link
|
||||||
AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender<bool>),
|
AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender<bool>),
|
||||||
/// Sends an unconsumed key event back to the embedder.
|
/// Sends an unconsumed key event back to the embedder.
|
||||||
|
@ -148,6 +141,8 @@ pub enum EmbedderMsg {
|
||||||
LoadComplete(TopLevelBrowsingContextId),
|
LoadComplete(TopLevelBrowsingContextId),
|
||||||
/// A pipeline panicked. First string is the reason, second one is the backtrace.
|
/// A pipeline panicked. First string is the reason, second one is the backtrace.
|
||||||
Panic(TopLevelBrowsingContextId, String, Option<String>),
|
Panic(TopLevelBrowsingContextId, String, Option<String>),
|
||||||
|
/// Servo has shut down
|
||||||
|
Shutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages from the painting thread and the constellation thread to the compositor thread.
|
/// Messages from the painting thread and the constellation thread to the compositor thread.
|
||||||
|
@ -196,6 +191,12 @@ pub enum Msg {
|
||||||
/// The load of a page has completed
|
/// The load of a page has completed
|
||||||
LoadComplete(TopLevelBrowsingContextId),
|
LoadComplete(TopLevelBrowsingContextId),
|
||||||
|
|
||||||
|
/// Get Window Informations size and position.
|
||||||
|
GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>),
|
||||||
|
/// Get screen size.
|
||||||
|
GetScreenSize(IpcSender<DeviceUintSize>),
|
||||||
|
/// Get screen available size.
|
||||||
|
GetScreenAvailSize(IpcSender<DeviceUintSize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Msg {
|
impl Debug for Msg {
|
||||||
|
@ -216,6 +217,9 @@ impl Debug for Msg {
|
||||||
Msg::Dispatch(..) => write!(f, "Dispatch"),
|
Msg::Dispatch(..) => write!(f, "Dispatch"),
|
||||||
Msg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"),
|
Msg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"),
|
||||||
Msg::LoadComplete(..) => write!(f, "LoadComplete"),
|
Msg::LoadComplete(..) => write!(f, "LoadComplete"),
|
||||||
|
Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
|
||||||
|
Msg::GetScreenSize(..) => write!(f, "GetScreenSize"),
|
||||||
|
Msg::GetScreenAvailSize(..) => write!(f, "GetScreenAvailSize"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,9 +231,6 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
|
EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
|
||||||
EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
|
EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
|
||||||
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
|
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
|
||||||
EmbedderMsg::GetClientWindow(..) => write!(f, "GetClientWindow"),
|
|
||||||
EmbedderMsg::GetScreenSize(..) => write!(f, "GetScreenSize"),
|
|
||||||
EmbedderMsg::GetScreenAvailSize(..) => write!(f, "GetScreenAvailSize"),
|
|
||||||
EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"),
|
EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"),
|
||||||
EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"),
|
EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"),
|
||||||
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
|
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
|
||||||
|
@ -240,6 +241,7 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"),
|
EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"),
|
||||||
EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"),
|
EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"),
|
||||||
EmbedderMsg::Panic(..) => write!(f, "Panic"),
|
EmbedderMsg::Panic(..) => write!(f, "Panic"),
|
||||||
|
EmbedderMsg::Shutdown => write!(f, "Shutdown"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,12 @@ use euclid::TypedScale;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
|
||||||
use net_traits::net_error_list::NetError;
|
use script_traits::{MouseButton, TouchEventType, TouchId};
|
||||||
use script_traits::{LoadData, MouseButton, TouchEventType, TouchId};
|
|
||||||
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::fmt::{Debug, Error, Formatter};
|
use std::fmt::{Debug, Error, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use style_traits::DevicePixel;
|
use style_traits::DevicePixel;
|
||||||
use style_traits::cursor::CursorKind;
|
|
||||||
use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintSize, DeviceUintRect, ScrollLocation};
|
use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintSize, DeviceUintRect, ScrollLocation};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -121,75 +119,39 @@ pub enum AnimationState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WindowMethods {
|
pub trait WindowMethods {
|
||||||
/// Returns the rendering area size in hardware pixels.
|
|
||||||
fn framebuffer_size(&self) -> DeviceUintSize;
|
|
||||||
/// Returns the position and size of the window within the rendering area.
|
|
||||||
fn window_rect(&self) -> DeviceUintRect;
|
|
||||||
/// Presents the window to the screen (perhaps by page flipping).
|
/// Presents the window to the screen (perhaps by page flipping).
|
||||||
fn present(&self);
|
fn present(&self);
|
||||||
|
|
||||||
/// Return the size of the window with head and borders and position of the window values
|
|
||||||
fn client_window(&self, ctx: TopLevelBrowsingContextId) -> (DeviceUintSize, DeviceIntPoint);
|
|
||||||
/// Return the size of the screen.
|
|
||||||
fn screen_size(&self, ctx: TopLevelBrowsingContextId) -> DeviceUintSize;
|
|
||||||
/// Return the available size of the screen.
|
|
||||||
fn screen_avail_size(&self, ctx: TopLevelBrowsingContextId) -> DeviceUintSize;
|
|
||||||
/// Set the size inside of borders and head
|
|
||||||
fn set_inner_size(&self, ctx: TopLevelBrowsingContextId, size: DeviceUintSize);
|
|
||||||
/// Set the window position
|
|
||||||
fn set_position(&self, ctx: TopLevelBrowsingContextId, point: DeviceIntPoint);
|
|
||||||
/// Set fullscreen state
|
|
||||||
fn set_fullscreen_state(&self, ctx: TopLevelBrowsingContextId, state: bool);
|
|
||||||
|
|
||||||
/// Sets the page title for the current page.
|
|
||||||
fn set_page_title(&self, ctx: TopLevelBrowsingContextId, title: Option<String>);
|
|
||||||
/// Called when the browser chrome should display a status message.
|
|
||||||
fn status(&self, ctx: TopLevelBrowsingContextId, Option<String>);
|
|
||||||
/// Called when the browser has started loading a frame.
|
|
||||||
fn load_start(&self, ctx: TopLevelBrowsingContextId);
|
|
||||||
/// Called when the browser is done loading a frame.
|
|
||||||
fn load_end(&self, ctx: TopLevelBrowsingContextId);
|
|
||||||
/// Called when the browser encounters an error while loading a URL
|
|
||||||
fn load_error(&self, ctx: TopLevelBrowsingContextId, code: NetError, url: String);
|
|
||||||
/// Wether or not to follow a link
|
|
||||||
fn allow_navigation(&self, ctx: TopLevelBrowsingContextId, url: ServoUrl, IpcSender<bool>);
|
|
||||||
/// Called when the <head> tag has finished parsing
|
|
||||||
fn head_parsed(&self, ctx: TopLevelBrowsingContextId);
|
|
||||||
/// Called when the history state has changed.
|
|
||||||
fn history_changed(&self, ctx: TopLevelBrowsingContextId, Vec<LoadData>, usize);
|
|
||||||
|
|
||||||
/// Returns the scale factor of the system (device pixels / device independent pixels).
|
|
||||||
fn hidpi_factor(&self) -> TypedScale<f32, DeviceIndependentPixel, DevicePixel>;
|
|
||||||
|
|
||||||
/// Returns a thread-safe object to wake up the window's event loop.
|
|
||||||
fn create_event_loop_waker(&self) -> Box<EventLoopWaker>;
|
|
||||||
|
|
||||||
/// Requests that the window system prepare a composite. Typically this will involve making
|
/// Requests that the window system prepare a composite. Typically this will involve making
|
||||||
/// some type of platform-specific graphics context current. Returns true if the composite may
|
/// some type of platform-specific graphics context current. Returns true if the composite may
|
||||||
/// proceed and false if it should not.
|
/// proceed and false if it should not.
|
||||||
fn prepare_for_composite(&self, width: DeviceUintLength, height: DeviceUintLength) -> bool;
|
fn prepare_for_composite(&self, width: DeviceUintLength, height: DeviceUintLength) -> bool;
|
||||||
|
|
||||||
/// Sets the cursor to be used in the window.
|
|
||||||
fn set_cursor(&self, cursor: CursorKind);
|
|
||||||
|
|
||||||
/// Process a key event.
|
|
||||||
fn handle_key(&self, ctx: Option<TopLevelBrowsingContextId>, ch: Option<char>, key: Key, mods: KeyModifiers);
|
|
||||||
|
|
||||||
/// Does this window support a clipboard
|
|
||||||
fn supports_clipboard(&self) -> bool;
|
|
||||||
|
|
||||||
/// Add a favicon
|
|
||||||
fn set_favicon(&self, ctx: TopLevelBrowsingContextId, url: ServoUrl);
|
|
||||||
|
|
||||||
/// Return the GL function pointer trait.
|
/// Return the GL function pointer trait.
|
||||||
fn gl(&self) -> Rc<gl::Gl>;
|
fn gl(&self) -> Rc<gl::Gl>;
|
||||||
|
/// Returns a thread-safe object to wake up the window's event loop.
|
||||||
|
fn create_event_loop_waker(&self) -> Box<EventLoopWaker>;
|
||||||
|
/// Get the coordinates of the native window, the screen and the framebuffer.
|
||||||
|
fn get_coordinates(&self) -> EmbedderCoordinates;
|
||||||
|
/// Does this window support a clipboard
|
||||||
|
fn supports_clipboard(&self) -> bool;
|
||||||
/// Set whether the application is currently animating.
|
/// Set whether the application is currently animating.
|
||||||
/// Typically, when animations are active, the window
|
/// Typically, when animations are active, the window
|
||||||
/// will want to avoid blocking on UI events, and just
|
/// will want to avoid blocking on UI events, and just
|
||||||
/// run the event loop at the vsync interval.
|
/// run the event loop at the vsync interval.
|
||||||
fn set_animation_state(&self, _state: AnimationState) {}
|
fn set_animation_state(&self, _state: AnimationState);
|
||||||
|
}
|
||||||
/// Called when a pipeline panics.
|
|
||||||
fn handle_panic(&self, browser_id: TopLevelBrowsingContextId, reason: String, backtrace: Option<String>);
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct EmbedderCoordinates {
|
||||||
|
/// The pixel density of the display.
|
||||||
|
pub hidpi_factor: TypedScale<f32, DeviceIndependentPixel, DevicePixel>,
|
||||||
|
/// Size of the screen.
|
||||||
|
pub screen: DeviceUintSize,
|
||||||
|
/// Size of the available screen space (screen without toolbars and docks).
|
||||||
|
pub screen_avail: DeviceUintSize,
|
||||||
|
/// Size of the native window.
|
||||||
|
pub window: (DeviceUintSize, DeviceIntPoint),
|
||||||
|
/// Size of the GL buffer in the window.
|
||||||
|
pub framebuffer: DeviceUintSize,
|
||||||
|
/// Coordinates of the document within the framebuffer.
|
||||||
|
pub viewport: DeviceUintRect,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1229,9 +1229,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
debug!("constellation got Alert message");
|
debug!("constellation got Alert message");
|
||||||
self.handle_alert(source_top_ctx_id, message, sender);
|
self.handle_alert(source_top_ctx_id, message, sender);
|
||||||
}
|
}
|
||||||
FromScriptMsg::GetClientWindow(send) => {
|
|
||||||
self.embedder_proxy.send(EmbedderMsg::GetClientWindow(source_top_ctx_id, send));
|
|
||||||
}
|
|
||||||
|
|
||||||
FromScriptMsg::MoveTo(point) => {
|
FromScriptMsg::MoveTo(point) => {
|
||||||
self.embedder_proxy.send(EmbedderMsg::MoveTo(source_top_ctx_id, point));
|
self.embedder_proxy.send(EmbedderMsg::MoveTo(source_top_ctx_id, point));
|
||||||
|
@ -1241,12 +1238,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.embedder_proxy.send(EmbedderMsg::ResizeTo(source_top_ctx_id, size));
|
self.embedder_proxy.send(EmbedderMsg::ResizeTo(source_top_ctx_id, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
FromScriptMsg::GetScreenSize(send) => {
|
FromScriptMsg::GetClientWindow(send) => {
|
||||||
self.embedder_proxy.send(EmbedderMsg::GetScreenSize(source_top_ctx_id, send));
|
self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send));
|
||||||
|
}
|
||||||
|
FromScriptMsg::GetScreenSize(send) => {
|
||||||
|
self.compositor_proxy.send(ToCompositorMsg::GetScreenSize(send));
|
||||||
}
|
}
|
||||||
|
|
||||||
FromScriptMsg::GetScreenAvailSize(send) => {
|
FromScriptMsg::GetScreenAvailSize(send) => {
|
||||||
self.embedder_proxy.send(EmbedderMsg::GetScreenAvailSize(source_top_ctx_id, send));
|
self.compositor_proxy.send(ToCompositorMsg::GetScreenAvailSize(send));
|
||||||
}
|
}
|
||||||
|
|
||||||
FromScriptMsg::Exit => {
|
FromScriptMsg::Exit => {
|
||||||
|
|
|
@ -136,8 +136,6 @@ pub enum ScriptMsg {
|
||||||
SetTitle(Option<String>),
|
SetTitle(Option<String>),
|
||||||
/// Send a key event
|
/// Send a key event
|
||||||
SendKeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
SendKeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||||
/// Get Window Informations size and position
|
|
||||||
GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>),
|
|
||||||
/// Move the window to a point
|
/// Move the window to a point
|
||||||
MoveTo(DeviceIntPoint),
|
MoveTo(DeviceIntPoint),
|
||||||
/// Resize the window to size
|
/// Resize the window to size
|
||||||
|
@ -155,6 +153,8 @@ pub enum ScriptMsg {
|
||||||
RegisterServiceWorker(ScopeThings, ServoUrl),
|
RegisterServiceWorker(ScopeThings, ServoUrl),
|
||||||
/// Enter or exit fullscreen
|
/// Enter or exit fullscreen
|
||||||
SetFullscreenState(bool),
|
SetFullscreenState(bool),
|
||||||
|
/// Get Window Informations size and position
|
||||||
|
GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>),
|
||||||
/// Get the screen size (pixel)
|
/// Get the screen size (pixel)
|
||||||
GetScreenSize(IpcSender<(DeviceUintSize)>),
|
GetScreenSize(IpcSender<(DeviceUintSize)>),
|
||||||
/// Get the available screen size (pixel)
|
/// Get the available screen size (pixel)
|
||||||
|
|
|
@ -74,8 +74,7 @@ use canvas::webgl_thread::WebGLThreads;
|
||||||
use compositing::{IOCompositor, ShutdownState, RenderNotifier};
|
use compositing::{IOCompositor, ShutdownState, RenderNotifier};
|
||||||
use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState};
|
use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState};
|
||||||
use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver};
|
use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver};
|
||||||
use compositing::windowing::WindowEvent;
|
use compositing::windowing::{WindowEvent, WindowMethods};
|
||||||
use compositing::windowing::WindowMethods;
|
|
||||||
use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent};
|
use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent};
|
||||||
use constellation::{FromCompositorLogger, FromScriptLogger};
|
use constellation::{FromCompositorLogger, FromScriptLogger};
|
||||||
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]
|
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]
|
||||||
|
@ -87,7 +86,6 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use log::{Log, LogMetadata, LogRecord};
|
use log::{Log, LogMetadata, LogRecord};
|
||||||
use msg::constellation_msg::KeyState;
|
|
||||||
use net::resource_thread::new_resource_threads;
|
use net::resource_thread::new_resource_threads;
|
||||||
use net_traits::IpcSend;
|
use net_traits::IpcSend;
|
||||||
use profile::mem as profile_mem;
|
use profile::mem as profile_mem;
|
||||||
|
@ -109,7 +107,7 @@ use webvr::{WebVRThread, WebVRCompositorHandler};
|
||||||
pub use gleam::gl;
|
pub use gleam::gl;
|
||||||
pub use servo_config as config;
|
pub use servo_config as config;
|
||||||
pub use servo_url as url;
|
pub use servo_url as url;
|
||||||
pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId;
|
pub use msg::constellation_msg::{KeyState, TopLevelBrowsingContextId as BrowserId};
|
||||||
|
|
||||||
/// The in-process interface to Servo.
|
/// The in-process interface to Servo.
|
||||||
///
|
///
|
||||||
|
@ -125,7 +123,8 @@ pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId;
|
||||||
pub struct Servo<Window: WindowMethods + 'static> {
|
pub struct Servo<Window: WindowMethods + 'static> {
|
||||||
compositor: IOCompositor<Window>,
|
compositor: IOCompositor<Window>,
|
||||||
constellation_chan: Sender<ConstellationMsg>,
|
constellation_chan: Sender<ConstellationMsg>,
|
||||||
embedder_receiver: EmbedderReceiver
|
embedder_receiver: EmbedderReceiver,
|
||||||
|
embedder_events: Vec<EmbedderMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
|
@ -158,17 +157,9 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
let mut resource_path = resources_dir_path().unwrap();
|
let mut resource_path = resources_dir_path().unwrap();
|
||||||
resource_path.push("shaders");
|
resource_path.push("shaders");
|
||||||
|
|
||||||
let (mut webrender, webrender_api_sender) = {
|
let coordinates = window.get_coordinates();
|
||||||
// TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up!
|
|
||||||
let scale_factor = window.hidpi_factor().get();
|
|
||||||
let device_pixel_ratio = match opts.device_pixels_per_px {
|
|
||||||
Some(device_pixels_per_px) => device_pixels_per_px,
|
|
||||||
None => match opts.output_file {
|
|
||||||
Some(_) => 1.0,
|
|
||||||
None => scale_factor,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let (mut webrender, webrender_api_sender) = {
|
||||||
let renderer_kind = if opts::get().should_use_osmesa() {
|
let renderer_kind = if opts::get().should_use_osmesa() {
|
||||||
RendererKind::OSMesa
|
RendererKind::OSMesa
|
||||||
} else {
|
} else {
|
||||||
|
@ -189,7 +180,7 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
let render_notifier = Box::new(RenderNotifier::new(compositor_proxy.clone()));
|
let render_notifier = Box::new(RenderNotifier::new(compositor_proxy.clone()));
|
||||||
|
|
||||||
webrender::Renderer::new(window.gl(), render_notifier, webrender::RendererOptions {
|
webrender::Renderer::new(window.gl(), render_notifier, webrender::RendererOptions {
|
||||||
device_pixel_ratio: device_pixel_ratio,
|
device_pixel_ratio: coordinates.hidpi_factor.get(),
|
||||||
resource_override_path: Some(resource_path),
|
resource_override_path: Some(resource_path),
|
||||||
enable_aa: opts.enable_text_antialiasing,
|
enable_aa: opts.enable_text_antialiasing,
|
||||||
debug_flags: debug_flags,
|
debug_flags: debug_flags,
|
||||||
|
@ -205,7 +196,7 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
|
|
||||||
let webrender_api = webrender_api_sender.create_api();
|
let webrender_api = webrender_api_sender.create_api();
|
||||||
let wr_document_layer = 0; //TODO
|
let wr_document_layer = 0; //TODO
|
||||||
let webrender_document = webrender_api.add_document(window.framebuffer_size(), wr_document_layer);
|
let webrender_document = webrender_api.add_document(coordinates.framebuffer, wr_document_layer);
|
||||||
|
|
||||||
// Important that this call is done in a single-threaded fashion, we
|
// Important that this call is done in a single-threaded fashion, we
|
||||||
// can't defer it after `create_constellation` has started.
|
// can't defer it after `create_constellation` has started.
|
||||||
|
@ -254,6 +245,7 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
compositor: compositor,
|
compositor: compositor,
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
embedder_receiver: embedder_receiver,
|
embedder_receiver: embedder_receiver,
|
||||||
|
embedder_events: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,108 +362,26 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
|
|
||||||
(_, ShutdownState::ShuttingDown) => {},
|
(_, ShutdownState::ShuttingDown) => {},
|
||||||
|
|
||||||
(EmbedderMsg::Status(top_level_browsing_context, message), ShutdownState::NotShuttingDown) => {
|
(EmbedderMsg::KeyEvent(top_level_browsing_context, ch, key, state, modified),
|
||||||
self.compositor.window.status(top_level_browsing_context, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::ChangePageTitle(top_level_browsing_context, title), ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.set_page_title(top_level_browsing_context, title);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::MoveTo(top_level_browsing_context, point),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.set_position(top_level_browsing_context, point);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::ResizeTo(top_level_browsing_context, size),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.set_inner_size(top_level_browsing_context, size);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::GetClientWindow(top_level_browsing_context, send),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
let rect = self.compositor.window.client_window(top_level_browsing_context);
|
|
||||||
if let Err(e) = send.send(rect) {
|
|
||||||
warn!("Sending response to get client window failed ({}).", e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::GetScreenSize(top_level_browsing_context, send),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
let rect = self.compositor.window.screen_size(top_level_browsing_context);
|
|
||||||
if let Err(e) = send.send(rect) {
|
|
||||||
warn!("Sending response to get screen size failed ({}).", e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::GetScreenAvailSize(top_level_browsing_context, send),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
let rect = self.compositor.window.screen_avail_size(top_level_browsing_context);
|
|
||||||
if let Err(e) = send.send(rect) {
|
|
||||||
warn!("Sending response to get screen available size failed ({}).", e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::AllowNavigation(top_level_browsing_context,
|
|
||||||
url,
|
|
||||||
response_chan),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.allow_navigation(top_level_browsing_context, url, response_chan);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::KeyEvent(top_level_browsing_context,
|
|
||||||
ch,
|
|
||||||
key,
|
|
||||||
state,
|
|
||||||
modified),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
ShutdownState::NotShuttingDown) => {
|
||||||
if state == KeyState::Pressed {
|
if state == KeyState::Pressed {
|
||||||
self.compositor.window.handle_key(top_level_browsing_context, ch, key, modified);
|
let msg = EmbedderMsg::KeyEvent(top_level_browsing_context, ch, key, state, modified);
|
||||||
|
self.embedder_events.push(msg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
(EmbedderMsg::SetCursor(cursor), ShutdownState::NotShuttingDown) => {
|
(msg, ShutdownState::NotShuttingDown) => {
|
||||||
self.compositor.window.set_cursor(cursor)
|
self.embedder_events.push(msg);
|
||||||
},
|
},
|
||||||
|
|
||||||
(EmbedderMsg::NewFavicon(top_level_browsing_context, url), ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.set_favicon(top_level_browsing_context, url);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::HeadParsed(top_level_browsing_context, ), ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.head_parsed(top_level_browsing_context, );
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::HistoryChanged(top_level_browsing_context, entries, current),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.history_changed(top_level_browsing_context, entries, current);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::SetFullscreenState(top_level_browsing_context, state),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.set_fullscreen_state(top_level_browsing_context, state);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::LoadStart(top_level_browsing_context), ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.load_start(top_level_browsing_context);
|
|
||||||
},
|
|
||||||
|
|
||||||
(EmbedderMsg::LoadComplete(top_level_browsing_context), ShutdownState::NotShuttingDown) => {
|
|
||||||
// Inform the embedder that the load has finished.
|
|
||||||
//
|
|
||||||
// TODO(pcwalton): Specify which frame's load completed.
|
|
||||||
self.compositor.window.load_end(top_level_browsing_context);
|
|
||||||
},
|
|
||||||
(EmbedderMsg::Panic(top_level_browsing_context, reason, backtrace),
|
|
||||||
ShutdownState::NotShuttingDown) => {
|
|
||||||
self.compositor.window.handle_panic(top_level_browsing_context, reason, backtrace);
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
|
pub fn get_events(&mut self) -> Vec<EmbedderMsg> {
|
||||||
|
::std::mem::replace(&mut self.embedder_events, Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_events(&mut self, events: Vec<WindowEvent>) {
|
||||||
if self.compositor.receive_messages() {
|
if self.compositor.receive_messages() {
|
||||||
self.receive_messages();
|
self.receive_messages();
|
||||||
}
|
}
|
||||||
|
@ -480,8 +390,9 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
}
|
}
|
||||||
if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown {
|
if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown {
|
||||||
self.compositor.perform_updates();
|
self.compositor.perform_updates();
|
||||||
|
} else {
|
||||||
|
self.embedder_events.push(EmbedderMsg::Shutdown);
|
||||||
}
|
}
|
||||||
self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repaint_synchronously(&mut self) {
|
pub fn repaint_synchronously(&mut self) {
|
||||||
|
|
|
@ -43,11 +43,9 @@ glutin = "0.13"
|
||||||
libservo = {path = "../../components/servo"}
|
libservo = {path = "../../components/servo"}
|
||||||
log = "0.3.5"
|
log = "0.3.5"
|
||||||
msg = {path = "../../components/msg"}
|
msg = {path = "../../components/msg"}
|
||||||
net_traits = {path = "../../components/net_traits"}
|
|
||||||
script_traits = {path = "../../components/script_traits"}
|
script_traits = {path = "../../components/script_traits"}
|
||||||
servo_geometry = {path = "../../components/geometry"}
|
servo_geometry = {path = "../../components/geometry"}
|
||||||
servo_config = {path = "../../components/config"}
|
servo_config = {path = "../../components/config"}
|
||||||
servo_url = {path = "../../components/url"}
|
|
||||||
style_traits = {path = "../../components/style_traits"}
|
style_traits = {path = "../../components/style_traits"}
|
||||||
tinyfiledialogs = "3.0"
|
tinyfiledialogs = "3.0"
|
||||||
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
|
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
|
||||||
|
|
313
ports/servo/browser.rs
Normal file
313
ports/servo/browser.rs
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use compositing::compositor_thread::EmbedderMsg;
|
||||||
|
use compositing::windowing::{WebRenderDebugOption, WindowEvent};
|
||||||
|
use euclid::{TypedPoint2D, TypedVector2D};
|
||||||
|
use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT};
|
||||||
|
use glutin_app::window::{Window, LINE_HEIGHT};
|
||||||
|
use msg::constellation_msg::{Key, TopLevelBrowsingContextId as BrowserId};
|
||||||
|
use msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection};
|
||||||
|
use script_traits::TouchEventType;
|
||||||
|
use servo::net_traits::pub_domains::is_reg_domain;
|
||||||
|
use servo::servo_url::ServoUrl;
|
||||||
|
use servo_config::prefs::PREFS;
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use tinyfiledialogs;
|
||||||
|
use webrender_api::ScrollLocation;
|
||||||
|
|
||||||
|
pub struct Browser {
|
||||||
|
current_url: Option<ServoUrl>,
|
||||||
|
/// id of the top level browsing context. It is unique as tabs
|
||||||
|
/// are not supported yet. None until created.
|
||||||
|
browser_id: Option<BrowserId>,
|
||||||
|
|
||||||
|
title: Option<String>,
|
||||||
|
status: Option<String>,
|
||||||
|
favicon: Option<ServoUrl>,
|
||||||
|
loading_state: Option<LoadingState>,
|
||||||
|
window: Rc<Window>,
|
||||||
|
event_queue: Vec<WindowEvent>,
|
||||||
|
shutdown_requested: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LoadingState {
|
||||||
|
Connecting,
|
||||||
|
Loading,
|
||||||
|
Loaded,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Browser {
|
||||||
|
pub fn new(window: Rc<Window>) -> Browser {
|
||||||
|
Browser {
|
||||||
|
title: None,
|
||||||
|
current_url: None,
|
||||||
|
browser_id: None,
|
||||||
|
status: None,
|
||||||
|
favicon: None,
|
||||||
|
loading_state: None,
|
||||||
|
window: window,
|
||||||
|
event_queue: Vec::new(),
|
||||||
|
shutdown_requested: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_events(&mut self) -> Vec<WindowEvent> {
|
||||||
|
mem::replace(&mut self.event_queue, Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_browser_id(&mut self, browser_id: BrowserId) {
|
||||||
|
self.browser_id = Some(browser_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
|
||||||
|
for event in events {
|
||||||
|
match event {
|
||||||
|
WindowEvent::KeyEvent(ch, key, state, mods) => {
|
||||||
|
self.handle_key_from_window(ch, key, state, mods);
|
||||||
|
},
|
||||||
|
event => {
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shutdown_requested(&self) -> bool {
|
||||||
|
self.shutdown_requested
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle key events before sending them to Servo.
|
||||||
|
fn handle_key_from_window(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
|
||||||
|
match (mods, ch, key) {
|
||||||
|
(CMD_OR_CONTROL, Some('r'), _) => {
|
||||||
|
if let Some(id) = self.browser_id {
|
||||||
|
self.event_queue.push(WindowEvent::Reload(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(CMD_OR_CONTROL, Some('l'), _) => {
|
||||||
|
if let Some(id) = self.browser_id {
|
||||||
|
let url: String = if let Some(ref current_url) = self.current_url {
|
||||||
|
current_url.to_string()
|
||||||
|
} else {
|
||||||
|
String::from("")
|
||||||
|
};
|
||||||
|
let title = "URL or search query";
|
||||||
|
if let Some(input) = tinyfiledialogs::input_box(title, title, &url) {
|
||||||
|
if let Some(url) = sanitize_url(&input) {
|
||||||
|
self.event_queue.push(WindowEvent::LoadUrl(id, url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(CMD_OR_CONTROL, Some('q'), _) => {
|
||||||
|
self.event_queue.push(WindowEvent::Quit);
|
||||||
|
}
|
||||||
|
(_, Some('3'), _) => if mods ^ KeyModifiers::CONTROL == KeyModifiers::SHIFT {
|
||||||
|
self.event_queue.push(WindowEvent::CaptureWebRender);
|
||||||
|
}
|
||||||
|
(KeyModifiers::CONTROL, None, Key::F10) => {
|
||||||
|
let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::RenderTargetDebug);
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
(KeyModifiers::CONTROL, None, Key::F11) => {
|
||||||
|
let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::TextureCacheDebug);
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
(KeyModifiers::CONTROL, None, Key::F12) => {
|
||||||
|
let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::Profiler);
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
(CMD_OR_ALT, None, Key::Right) | (KeyModifiers::NONE, None, Key::NavigateForward) => {
|
||||||
|
if let Some(id) = self.browser_id {
|
||||||
|
let event = WindowEvent::Navigation(id, TraversalDirection::Forward(1));
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(CMD_OR_ALT, None, Key::Left) | (KeyModifiers::NONE, None, Key::NavigateBackward) => {
|
||||||
|
if let Some(id) = self.browser_id {
|
||||||
|
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(KeyModifiers::NONE, None, Key::Escape) => {
|
||||||
|
self.event_queue.push(WindowEvent::Quit);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let event = self.platform_handle_key(key, mods);
|
||||||
|
self.event_queue.push(event.unwrap_or(WindowEvent::KeyEvent(ch, key, state, mods)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "win"))]
|
||||||
|
fn platform_handle_key(&self, key: Key, mods: KeyModifiers) -> Option<WindowEvent> {
|
||||||
|
match (mods, key, self.browser_id) {
|
||||||
|
(CMD_OR_CONTROL, Key::LeftBracket, Some(id)) => {
|
||||||
|
Some(WindowEvent::Navigation(id, TraversalDirection::Back(1)))
|
||||||
|
}
|
||||||
|
(CMD_OR_CONTROL, Key::RightBracket, Some(id)) => {
|
||||||
|
Some(WindowEvent::Navigation(id, TraversalDirection::Forward(1)))
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "win")]
|
||||||
|
fn platform_handle_key(&self, key: Key, mods: KeyModifiers) -> Option<WindowEvent> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle key events after they have been handled by Servo.
|
||||||
|
fn handle_key_from_servo(&mut self, _: Option<BrowserId>, ch: Option<char>,
|
||||||
|
key: Key, _: KeyState, mods: KeyModifiers) {
|
||||||
|
match (mods, ch, key) {
|
||||||
|
(_, Some('+'), _) => {
|
||||||
|
if mods & !KeyModifiers::SHIFT == CMD_OR_CONTROL {
|
||||||
|
self.event_queue.push(WindowEvent::Zoom(1.1));
|
||||||
|
} else if mods & !KeyModifiers::SHIFT == CMD_OR_CONTROL | KeyModifiers::ALT {
|
||||||
|
self.event_queue.push(WindowEvent::PinchZoom(1.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(CMD_OR_CONTROL, Some('-'), _) => {
|
||||||
|
self.event_queue.push(WindowEvent::Zoom(1.0 / 1.1));
|
||||||
|
}
|
||||||
|
(_, Some('-'), _) if mods == CMD_OR_CONTROL | KeyModifiers::ALT => {
|
||||||
|
self.event_queue.push(WindowEvent::PinchZoom(1.0 / 1.1));
|
||||||
|
}
|
||||||
|
(CMD_OR_CONTROL, Some('0'), _) => {
|
||||||
|
self.event_queue.push(WindowEvent::ResetZoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
(KeyModifiers::NONE, None, Key::PageDown) => {
|
||||||
|
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(0.0,
|
||||||
|
-self.window.page_height() + 2.0 * LINE_HEIGHT));
|
||||||
|
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
||||||
|
}
|
||||||
|
(KeyModifiers::NONE, None, Key::PageUp) => {
|
||||||
|
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(0.0,
|
||||||
|
self.window.page_height() - 2.0 * LINE_HEIGHT));
|
||||||
|
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
||||||
|
}
|
||||||
|
|
||||||
|
(KeyModifiers::NONE, None, Key::Home) => {
|
||||||
|
self.scroll_window_from_key(ScrollLocation::Start, TouchEventType::Move);
|
||||||
|
}
|
||||||
|
|
||||||
|
(KeyModifiers::NONE, None, Key::End) => {
|
||||||
|
self.scroll_window_from_key(ScrollLocation::End, TouchEventType::Move);
|
||||||
|
}
|
||||||
|
|
||||||
|
(KeyModifiers::NONE, None, Key::Up) => {
|
||||||
|
self.scroll_window_from_key(ScrollLocation::Delta(TypedVector2D::new(0.0, 3.0 * LINE_HEIGHT)),
|
||||||
|
TouchEventType::Move);
|
||||||
|
}
|
||||||
|
(KeyModifiers::NONE, None, Key::Down) => {
|
||||||
|
self.scroll_window_from_key(ScrollLocation::Delta(TypedVector2D::new(0.0, -3.0 * LINE_HEIGHT)),
|
||||||
|
TouchEventType::Move);
|
||||||
|
}
|
||||||
|
(KeyModifiers::NONE, None, Key::Left) => {
|
||||||
|
self.scroll_window_from_key(ScrollLocation::Delta(TypedVector2D::new(LINE_HEIGHT, 0.0)),
|
||||||
|
TouchEventType::Move);
|
||||||
|
}
|
||||||
|
(KeyModifiers::NONE, None, Key::Right) => {
|
||||||
|
self.scroll_window_from_key(ScrollLocation::Delta(TypedVector2D::new(-LINE_HEIGHT, 0.0)),
|
||||||
|
TouchEventType::Move);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scroll_window_from_key(&mut self, scroll_location: ScrollLocation, phase: TouchEventType) {
|
||||||
|
let event = WindowEvent::Scroll(scroll_location, TypedPoint2D::zero(), phase);
|
||||||
|
self.event_queue.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_servo_events(&mut self, events: Vec<EmbedderMsg>) {
|
||||||
|
for event in events {
|
||||||
|
match event {
|
||||||
|
EmbedderMsg::Status(_browser_id, status) => {
|
||||||
|
self.status = status;
|
||||||
|
},
|
||||||
|
EmbedderMsg::ChangePageTitle(_browser_id, title) => {
|
||||||
|
self.title = title;
|
||||||
|
|
||||||
|
let fallback_title: String = if let Some(ref current_url) = self.current_url {
|
||||||
|
current_url.to_string()
|
||||||
|
} else {
|
||||||
|
String::from("Untitled")
|
||||||
|
};
|
||||||
|
let title = match self.title {
|
||||||
|
Some(ref title) if title.len() > 0 => &**title,
|
||||||
|
_ => &fallback_title,
|
||||||
|
};
|
||||||
|
let title = format!("{} - Servo", title);
|
||||||
|
self.window.set_title(&title);
|
||||||
|
}
|
||||||
|
EmbedderMsg::MoveTo(_browser_id, point) => {
|
||||||
|
self.window.set_position(point);
|
||||||
|
}
|
||||||
|
EmbedderMsg::ResizeTo(_browser_id, size) => {
|
||||||
|
self.window.set_inner_size(size);
|
||||||
|
}
|
||||||
|
EmbedderMsg::AllowNavigation(_browser_id, _url, response_chan) => {
|
||||||
|
if let Err(e) = response_chan.send(true) {
|
||||||
|
warn!("Failed to send allow_navigation() response: {}", e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EmbedderMsg::KeyEvent(browser_id, ch, key, state, modified) => {
|
||||||
|
self.handle_key_from_servo(browser_id, ch, key, state, modified);
|
||||||
|
}
|
||||||
|
EmbedderMsg::SetCursor(cursor) => {
|
||||||
|
self.window.set_cursor(cursor);
|
||||||
|
}
|
||||||
|
EmbedderMsg::NewFavicon(_browser_id, url) => {
|
||||||
|
self.favicon = Some(url);
|
||||||
|
}
|
||||||
|
EmbedderMsg::HeadParsed(_browser_id, ) => {
|
||||||
|
self.loading_state = Some(LoadingState::Loading);
|
||||||
|
}
|
||||||
|
EmbedderMsg::HistoryChanged(_browser_id, entries, current) => {
|
||||||
|
self.current_url = Some(entries[current].url.clone());
|
||||||
|
}
|
||||||
|
EmbedderMsg::SetFullscreenState(_browser_id, state) => {
|
||||||
|
self.window.set_fullscreen(state);
|
||||||
|
}
|
||||||
|
EmbedderMsg::LoadStart(_browser_id) => {
|
||||||
|
self.loading_state = Some(LoadingState::Connecting);
|
||||||
|
}
|
||||||
|
EmbedderMsg::LoadComplete(_browser_id) => {
|
||||||
|
self.loading_state = Some(LoadingState::Loaded);
|
||||||
|
}
|
||||||
|
EmbedderMsg::Shutdown => {
|
||||||
|
self.shutdown_requested = true;
|
||||||
|
},
|
||||||
|
EmbedderMsg::Panic(_browser_id, _reason, _backtrace) => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_url(request: &str) -> Option<ServoUrl> {
|
||||||
|
let request = request.trim();
|
||||||
|
ServoUrl::parse(&request).ok()
|
||||||
|
.or_else(|| {
|
||||||
|
if request.contains('/') || is_reg_domain(request) {
|
||||||
|
ServoUrl::parse(&format!("http://{}", request)).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}).or_else(|| {
|
||||||
|
PREFS.get("shell.searchpage").as_string().and_then(|s: &str| {
|
||||||
|
let url = s.replace("%s", request);
|
||||||
|
ServoUrl::parse(&url).ok()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
352
ports/servo/glutin_app/keyutils.rs
Normal file
352
ports/servo/glutin_app/keyutils.rs
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use msg::constellation_msg::{self, Key, KeyModifiers};
|
||||||
|
use winit::{self, VirtualKeyCode};
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct GlutinKeyModifiers: u8 {
|
||||||
|
const LEFT_CONTROL = 1;
|
||||||
|
const RIGHT_CONTROL = 2;
|
||||||
|
const LEFT_SHIFT = 4;
|
||||||
|
const RIGHT_SHIFT = 8;
|
||||||
|
const LEFT_ALT = 16;
|
||||||
|
const RIGHT_ALT = 32;
|
||||||
|
const LEFT_SUPER = 64;
|
||||||
|
const RIGHT_SUPER = 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some shortcuts use Cmd on Mac and Control on other systems.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub const CMD_OR_CONTROL: KeyModifiers = KeyModifiers::SUPER;
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
pub const CMD_OR_CONTROL: KeyModifiers = KeyModifiers::CONTROL;
|
||||||
|
|
||||||
|
// Some shortcuts use Cmd on Mac and Alt on other systems.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub const CMD_OR_ALT: KeyModifiers = KeyModifiers::SUPER;
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
pub const CMD_OR_ALT: KeyModifiers = KeyModifiers::ALT;
|
||||||
|
|
||||||
|
pub fn char_to_script_key(c: char) -> Option<constellation_msg::Key> {
|
||||||
|
match c {
|
||||||
|
' ' => Some(Key::Space),
|
||||||
|
'"' => Some(Key::Apostrophe),
|
||||||
|
'\'' => Some(Key::Apostrophe),
|
||||||
|
'<' => Some(Key::Comma),
|
||||||
|
',' => Some(Key::Comma),
|
||||||
|
'_' => Some(Key::Minus),
|
||||||
|
'-' => Some(Key::Minus),
|
||||||
|
'>' => Some(Key::Period),
|
||||||
|
'.' => Some(Key::Period),
|
||||||
|
'?' => Some(Key::Slash),
|
||||||
|
'/' => Some(Key::Slash),
|
||||||
|
'~' => Some(Key::GraveAccent),
|
||||||
|
'`' => Some(Key::GraveAccent),
|
||||||
|
')' => Some(Key::Num0),
|
||||||
|
'0' => Some(Key::Num0),
|
||||||
|
'!' => Some(Key::Num1),
|
||||||
|
'1' => Some(Key::Num1),
|
||||||
|
'@' => Some(Key::Num2),
|
||||||
|
'2' => Some(Key::Num2),
|
||||||
|
'#' => Some(Key::Num3),
|
||||||
|
'3' => Some(Key::Num3),
|
||||||
|
'$' => Some(Key::Num4),
|
||||||
|
'4' => Some(Key::Num4),
|
||||||
|
'%' => Some(Key::Num5),
|
||||||
|
'5' => Some(Key::Num5),
|
||||||
|
'^' => Some(Key::Num6),
|
||||||
|
'6' => Some(Key::Num6),
|
||||||
|
'&' => Some(Key::Num7),
|
||||||
|
'7' => Some(Key::Num7),
|
||||||
|
'*' => Some(Key::Num8),
|
||||||
|
'8' => Some(Key::Num8),
|
||||||
|
'(' => Some(Key::Num9),
|
||||||
|
'9' => Some(Key::Num9),
|
||||||
|
':' => Some(Key::Semicolon),
|
||||||
|
';' => Some(Key::Semicolon),
|
||||||
|
'+' => Some(Key::Equal),
|
||||||
|
'=' => Some(Key::Equal),
|
||||||
|
'A' => Some(Key::A),
|
||||||
|
'a' => Some(Key::A),
|
||||||
|
'B' => Some(Key::B),
|
||||||
|
'b' => Some(Key::B),
|
||||||
|
'C' => Some(Key::C),
|
||||||
|
'c' => Some(Key::C),
|
||||||
|
'D' => Some(Key::D),
|
||||||
|
'd' => Some(Key::D),
|
||||||
|
'E' => Some(Key::E),
|
||||||
|
'e' => Some(Key::E),
|
||||||
|
'F' => Some(Key::F),
|
||||||
|
'f' => Some(Key::F),
|
||||||
|
'G' => Some(Key::G),
|
||||||
|
'g' => Some(Key::G),
|
||||||
|
'H' => Some(Key::H),
|
||||||
|
'h' => Some(Key::H),
|
||||||
|
'I' => Some(Key::I),
|
||||||
|
'i' => Some(Key::I),
|
||||||
|
'J' => Some(Key::J),
|
||||||
|
'j' => Some(Key::J),
|
||||||
|
'K' => Some(Key::K),
|
||||||
|
'k' => Some(Key::K),
|
||||||
|
'L' => Some(Key::L),
|
||||||
|
'l' => Some(Key::L),
|
||||||
|
'M' => Some(Key::M),
|
||||||
|
'm' => Some(Key::M),
|
||||||
|
'N' => Some(Key::N),
|
||||||
|
'n' => Some(Key::N),
|
||||||
|
'O' => Some(Key::O),
|
||||||
|
'o' => Some(Key::O),
|
||||||
|
'P' => Some(Key::P),
|
||||||
|
'p' => Some(Key::P),
|
||||||
|
'Q' => Some(Key::Q),
|
||||||
|
'q' => Some(Key::Q),
|
||||||
|
'R' => Some(Key::R),
|
||||||
|
'r' => Some(Key::R),
|
||||||
|
'S' => Some(Key::S),
|
||||||
|
's' => Some(Key::S),
|
||||||
|
'T' => Some(Key::T),
|
||||||
|
't' => Some(Key::T),
|
||||||
|
'U' => Some(Key::U),
|
||||||
|
'u' => Some(Key::U),
|
||||||
|
'V' => Some(Key::V),
|
||||||
|
'v' => Some(Key::V),
|
||||||
|
'W' => Some(Key::W),
|
||||||
|
'w' => Some(Key::W),
|
||||||
|
'X' => Some(Key::X),
|
||||||
|
'x' => Some(Key::X),
|
||||||
|
'Y' => Some(Key::Y),
|
||||||
|
'y' => Some(Key::Y),
|
||||||
|
'Z' => Some(Key::Z),
|
||||||
|
'z' => Some(Key::Z),
|
||||||
|
'{' => Some(Key::LeftBracket),
|
||||||
|
'[' => Some(Key::LeftBracket),
|
||||||
|
'|' => Some(Key::Backslash),
|
||||||
|
'\\' => Some(Key::Backslash),
|
||||||
|
'}' => Some(Key::RightBracket),
|
||||||
|
']' => Some(Key::RightBracket),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn glutin_key_to_script_key(key: winit::VirtualKeyCode) -> Result<constellation_msg::Key, ()> {
|
||||||
|
// TODO(negge): add more key mappings
|
||||||
|
match key {
|
||||||
|
VirtualKeyCode::A => Ok(Key::A),
|
||||||
|
VirtualKeyCode::B => Ok(Key::B),
|
||||||
|
VirtualKeyCode::C => Ok(Key::C),
|
||||||
|
VirtualKeyCode::D => Ok(Key::D),
|
||||||
|
VirtualKeyCode::E => Ok(Key::E),
|
||||||
|
VirtualKeyCode::F => Ok(Key::F),
|
||||||
|
VirtualKeyCode::G => Ok(Key::G),
|
||||||
|
VirtualKeyCode::H => Ok(Key::H),
|
||||||
|
VirtualKeyCode::I => Ok(Key::I),
|
||||||
|
VirtualKeyCode::J => Ok(Key::J),
|
||||||
|
VirtualKeyCode::K => Ok(Key::K),
|
||||||
|
VirtualKeyCode::L => Ok(Key::L),
|
||||||
|
VirtualKeyCode::M => Ok(Key::M),
|
||||||
|
VirtualKeyCode::N => Ok(Key::N),
|
||||||
|
VirtualKeyCode::O => Ok(Key::O),
|
||||||
|
VirtualKeyCode::P => Ok(Key::P),
|
||||||
|
VirtualKeyCode::Q => Ok(Key::Q),
|
||||||
|
VirtualKeyCode::R => Ok(Key::R),
|
||||||
|
VirtualKeyCode::S => Ok(Key::S),
|
||||||
|
VirtualKeyCode::T => Ok(Key::T),
|
||||||
|
VirtualKeyCode::U => Ok(Key::U),
|
||||||
|
VirtualKeyCode::V => Ok(Key::V),
|
||||||
|
VirtualKeyCode::W => Ok(Key::W),
|
||||||
|
VirtualKeyCode::X => Ok(Key::X),
|
||||||
|
VirtualKeyCode::Y => Ok(Key::Y),
|
||||||
|
VirtualKeyCode::Z => Ok(Key::Z),
|
||||||
|
|
||||||
|
VirtualKeyCode::Numpad0 => Ok(Key::Kp0),
|
||||||
|
VirtualKeyCode::Numpad1 => Ok(Key::Kp1),
|
||||||
|
VirtualKeyCode::Numpad2 => Ok(Key::Kp2),
|
||||||
|
VirtualKeyCode::Numpad3 => Ok(Key::Kp3),
|
||||||
|
VirtualKeyCode::Numpad4 => Ok(Key::Kp4),
|
||||||
|
VirtualKeyCode::Numpad5 => Ok(Key::Kp5),
|
||||||
|
VirtualKeyCode::Numpad6 => Ok(Key::Kp6),
|
||||||
|
VirtualKeyCode::Numpad7 => Ok(Key::Kp7),
|
||||||
|
VirtualKeyCode::Numpad8 => Ok(Key::Kp8),
|
||||||
|
VirtualKeyCode::Numpad9 => Ok(Key::Kp9),
|
||||||
|
|
||||||
|
VirtualKeyCode::Key0 => Ok(Key::Num0),
|
||||||
|
VirtualKeyCode::Key1 => Ok(Key::Num1),
|
||||||
|
VirtualKeyCode::Key2 => Ok(Key::Num2),
|
||||||
|
VirtualKeyCode::Key3 => Ok(Key::Num3),
|
||||||
|
VirtualKeyCode::Key4 => Ok(Key::Num4),
|
||||||
|
VirtualKeyCode::Key5 => Ok(Key::Num5),
|
||||||
|
VirtualKeyCode::Key6 => Ok(Key::Num6),
|
||||||
|
VirtualKeyCode::Key7 => Ok(Key::Num7),
|
||||||
|
VirtualKeyCode::Key8 => Ok(Key::Num8),
|
||||||
|
VirtualKeyCode::Key9 => Ok(Key::Num9),
|
||||||
|
|
||||||
|
VirtualKeyCode::Return => Ok(Key::Enter),
|
||||||
|
VirtualKeyCode::Space => Ok(Key::Space),
|
||||||
|
VirtualKeyCode::Escape => Ok(Key::Escape),
|
||||||
|
VirtualKeyCode::Equals => Ok(Key::Equal),
|
||||||
|
VirtualKeyCode::Minus => Ok(Key::Minus),
|
||||||
|
VirtualKeyCode::Back => Ok(Key::Backspace),
|
||||||
|
VirtualKeyCode::PageDown => Ok(Key::PageDown),
|
||||||
|
VirtualKeyCode::PageUp => Ok(Key::PageUp),
|
||||||
|
|
||||||
|
VirtualKeyCode::Insert => Ok(Key::Insert),
|
||||||
|
VirtualKeyCode::Home => Ok(Key::Home),
|
||||||
|
VirtualKeyCode::Delete => Ok(Key::Delete),
|
||||||
|
VirtualKeyCode::End => Ok(Key::End),
|
||||||
|
|
||||||
|
VirtualKeyCode::Left => Ok(Key::Left),
|
||||||
|
VirtualKeyCode::Up => Ok(Key::Up),
|
||||||
|
VirtualKeyCode::Right => Ok(Key::Right),
|
||||||
|
VirtualKeyCode::Down => Ok(Key::Down),
|
||||||
|
|
||||||
|
VirtualKeyCode::LShift => Ok(Key::LeftShift),
|
||||||
|
VirtualKeyCode::LControl => Ok(Key::LeftControl),
|
||||||
|
VirtualKeyCode::LAlt => Ok(Key::LeftAlt),
|
||||||
|
VirtualKeyCode::LWin => Ok(Key::LeftSuper),
|
||||||
|
VirtualKeyCode::RShift => Ok(Key::RightShift),
|
||||||
|
VirtualKeyCode::RControl => Ok(Key::RightControl),
|
||||||
|
VirtualKeyCode::RAlt => Ok(Key::RightAlt),
|
||||||
|
VirtualKeyCode::RWin => Ok(Key::RightSuper),
|
||||||
|
|
||||||
|
VirtualKeyCode::Apostrophe => Ok(Key::Apostrophe),
|
||||||
|
VirtualKeyCode::Backslash => Ok(Key::Backslash),
|
||||||
|
VirtualKeyCode::Comma => Ok(Key::Comma),
|
||||||
|
VirtualKeyCode::Grave => Ok(Key::GraveAccent),
|
||||||
|
VirtualKeyCode::LBracket => Ok(Key::LeftBracket),
|
||||||
|
VirtualKeyCode::Period => Ok(Key::Period),
|
||||||
|
VirtualKeyCode::RBracket => Ok(Key::RightBracket),
|
||||||
|
VirtualKeyCode::Semicolon => Ok(Key::Semicolon),
|
||||||
|
VirtualKeyCode::Slash => Ok(Key::Slash),
|
||||||
|
VirtualKeyCode::Tab => Ok(Key::Tab),
|
||||||
|
VirtualKeyCode::Subtract => Ok(Key::Minus),
|
||||||
|
|
||||||
|
VirtualKeyCode::F1 => Ok(Key::F1),
|
||||||
|
VirtualKeyCode::F2 => Ok(Key::F2),
|
||||||
|
VirtualKeyCode::F3 => Ok(Key::F3),
|
||||||
|
VirtualKeyCode::F4 => Ok(Key::F4),
|
||||||
|
VirtualKeyCode::F5 => Ok(Key::F5),
|
||||||
|
VirtualKeyCode::F6 => Ok(Key::F6),
|
||||||
|
VirtualKeyCode::F7 => Ok(Key::F7),
|
||||||
|
VirtualKeyCode::F8 => Ok(Key::F8),
|
||||||
|
VirtualKeyCode::F9 => Ok(Key::F9),
|
||||||
|
VirtualKeyCode::F10 => Ok(Key::F10),
|
||||||
|
VirtualKeyCode::F11 => Ok(Key::F11),
|
||||||
|
VirtualKeyCode::F12 => Ok(Key::F12),
|
||||||
|
|
||||||
|
VirtualKeyCode::NavigateBackward => Ok(Key::NavigateBackward),
|
||||||
|
VirtualKeyCode::NavigateForward => Ok(Key::NavigateForward),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn glutin_mods_to_script_mods(modifiers: GlutinKeyModifiers) -> constellation_msg::KeyModifiers {
|
||||||
|
let mut result = constellation_msg::KeyModifiers::empty();
|
||||||
|
if modifiers.intersects(GlutinKeyModifiers::LEFT_SHIFT | GlutinKeyModifiers::RIGHT_SHIFT) {
|
||||||
|
result.insert(KeyModifiers::SHIFT);
|
||||||
|
}
|
||||||
|
if modifiers.intersects(GlutinKeyModifiers::LEFT_CONTROL | GlutinKeyModifiers::RIGHT_CONTROL) {
|
||||||
|
result.insert(KeyModifiers::CONTROL);
|
||||||
|
}
|
||||||
|
if modifiers.intersects(GlutinKeyModifiers::LEFT_ALT | GlutinKeyModifiers::RIGHT_ALT) {
|
||||||
|
result.insert(KeyModifiers::ALT);
|
||||||
|
}
|
||||||
|
if modifiers.intersects(GlutinKeyModifiers::LEFT_SUPER | GlutinKeyModifiers::RIGHT_SUPER) {
|
||||||
|
result.insert(KeyModifiers::SUPER);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_printable(key_code: VirtualKeyCode) -> bool {
|
||||||
|
use winit::VirtualKeyCode::*;
|
||||||
|
match key_code {
|
||||||
|
Escape |
|
||||||
|
F1 |
|
||||||
|
F2 |
|
||||||
|
F3 |
|
||||||
|
F4 |
|
||||||
|
F5 |
|
||||||
|
F6 |
|
||||||
|
F7 |
|
||||||
|
F8 |
|
||||||
|
F9 |
|
||||||
|
F10 |
|
||||||
|
F11 |
|
||||||
|
F12 |
|
||||||
|
F13 |
|
||||||
|
F14 |
|
||||||
|
F15 |
|
||||||
|
Snapshot |
|
||||||
|
Scroll |
|
||||||
|
Pause |
|
||||||
|
Insert |
|
||||||
|
Home |
|
||||||
|
Delete |
|
||||||
|
End |
|
||||||
|
PageDown |
|
||||||
|
PageUp |
|
||||||
|
Left |
|
||||||
|
Up |
|
||||||
|
Right |
|
||||||
|
Down |
|
||||||
|
Back |
|
||||||
|
LAlt |
|
||||||
|
LControl |
|
||||||
|
LMenu |
|
||||||
|
LShift |
|
||||||
|
LWin |
|
||||||
|
Mail |
|
||||||
|
MediaSelect |
|
||||||
|
MediaStop |
|
||||||
|
Mute |
|
||||||
|
MyComputer |
|
||||||
|
NavigateForward |
|
||||||
|
NavigateBackward |
|
||||||
|
NextTrack |
|
||||||
|
NoConvert |
|
||||||
|
PlayPause |
|
||||||
|
Power |
|
||||||
|
PrevTrack |
|
||||||
|
RAlt |
|
||||||
|
RControl |
|
||||||
|
RMenu |
|
||||||
|
RShift |
|
||||||
|
RWin |
|
||||||
|
Sleep |
|
||||||
|
Stop |
|
||||||
|
VolumeDown |
|
||||||
|
VolumeUp |
|
||||||
|
Wake |
|
||||||
|
WebBack |
|
||||||
|
WebFavorites |
|
||||||
|
WebForward |
|
||||||
|
WebHome |
|
||||||
|
WebRefresh |
|
||||||
|
WebSearch |
|
||||||
|
WebStop => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Detect if given char is default ignorable in unicode
|
||||||
|
/// http://www.unicode.org/L2/L2002/02368-default-ignorable.pdf
|
||||||
|
pub fn is_identifier_ignorable(ch: &char) -> bool {
|
||||||
|
match *ch {
|
||||||
|
'\u{0000}'...'\u{0008}' | '\u{000E}'...'\u{001F}' |
|
||||||
|
'\u{007F}'...'\u{0084}' | '\u{0086}'...'\u{009F}' |
|
||||||
|
'\u{06DD}' | '\u{070F}' |
|
||||||
|
'\u{180B}'...'\u{180D}' | '\u{180E}' |
|
||||||
|
'\u{200C}'...'\u{200F}' |
|
||||||
|
'\u{202A}'...'\u{202E}' | '\u{2060}'...'\u{2063}' |
|
||||||
|
'\u{2064}'...'\u{2069}' | '\u{206A}'...'\u{206F}' |
|
||||||
|
'\u{FE00}'...'\u{FE0F}' | '\u{FEFF}' |
|
||||||
|
'\u{FFF0}'...'\u{FFF8}' | '\u{FFF9}'...'\u{FFFB}' |
|
||||||
|
'\u{1D173}'...'\u{1D17A}' | '\u{E0000}' |
|
||||||
|
'\u{E0001}' |
|
||||||
|
'\u{E0002}'...'\u{E001F}' | '\u{E0020}'...'\u{E007F}' |
|
||||||
|
'\u{E0080}'...'\u{E0FFF}' => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! A simple application that uses glutin to open a window for Servo to display in.
|
//! A simple application that uses glutin to open a window for Servo to display in.
|
||||||
|
|
||||||
|
pub mod keyutils;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
||||||
use servo_config::opts;
|
use servo_config::opts;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,13 +29,11 @@ extern crate glutin;
|
||||||
// The window backed by glutin
|
// The window backed by glutin
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate msg;
|
extern crate msg;
|
||||||
extern crate net_traits;
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys;
|
#[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys;
|
||||||
extern crate script_traits;
|
extern crate script_traits;
|
||||||
extern crate servo;
|
extern crate servo;
|
||||||
extern crate servo_config;
|
extern crate servo_config;
|
||||||
extern crate servo_geometry;
|
extern crate servo_geometry;
|
||||||
extern crate servo_url;
|
|
||||||
#[cfg(all(feature = "unstable", not(target_os = "android")))]
|
#[cfg(all(feature = "unstable", not(target_os = "android")))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate sig;
|
extern crate sig;
|
||||||
|
@ -63,6 +61,8 @@ use std::panic;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
|
mod browser;
|
||||||
|
|
||||||
pub mod platform {
|
pub mod platform {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub use platform::macos::deinit;
|
pub use platform::macos::deinit;
|
||||||
|
@ -163,6 +163,8 @@ fn main() {
|
||||||
|
|
||||||
let window = glutin_app::create_window();
|
let window = glutin_app::create_window();
|
||||||
|
|
||||||
|
let mut browser = browser::Browser::new(window.clone());
|
||||||
|
|
||||||
// If the url is not provided, we fallback to the homepage in PREFS,
|
// If the url is not provided, we fallback to the homepage in PREFS,
|
||||||
// or a blank page in case the homepage is not set either.
|
// or a blank page in case the homepage is not set either.
|
||||||
let cwd = env::current_dir().unwrap();
|
let cwd = env::current_dir().unwrap();
|
||||||
|
@ -178,22 +180,40 @@ fn main() {
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
|
servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
|
||||||
let browser_id = receiver.recv().unwrap();
|
let browser_id = receiver.recv().unwrap();
|
||||||
window.set_browser_id(browser_id);
|
browser.set_browser_id(browser_id);
|
||||||
servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);
|
servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);
|
||||||
|
|
||||||
servo.setup_logging();
|
servo.setup_logging();
|
||||||
|
|
||||||
window.run(|| {
|
window.run(|| {
|
||||||
let events = window.get_events();
|
let win_events = window.get_events();
|
||||||
let need_resize = events.iter().any(|e| match *e {
|
|
||||||
|
// FIXME: this could be handled by Servo. We don't need
|
||||||
|
// a repaint_synchronously function exposed.
|
||||||
|
let need_resize = win_events.iter().any(|e| match *e {
|
||||||
WindowEvent::Resize => true,
|
WindowEvent::Resize => true,
|
||||||
_ => false
|
_ => false,
|
||||||
});
|
});
|
||||||
let stop = !servo.handle_events(events);
|
|
||||||
|
browser.handle_window_events(win_events);
|
||||||
|
|
||||||
|
let mut servo_events = servo.get_events();
|
||||||
|
loop {
|
||||||
|
browser.handle_servo_events(servo_events);
|
||||||
|
servo.handle_events(browser.get_events());
|
||||||
|
if browser.shutdown_requested() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
servo_events = servo.get_events();
|
||||||
|
if servo_events.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if need_resize {
|
if need_resize {
|
||||||
servo.repaint_synchronously();
|
servo.repaint_synchronously();
|
||||||
}
|
}
|
||||||
stop
|
false
|
||||||
});
|
});
|
||||||
|
|
||||||
servo.deinit();
|
servo.deinit();
|
||||||
|
|
|
@ -63,7 +63,6 @@
|
||||||
"network.http-cache.disabled": false,
|
"network.http-cache.disabled": false,
|
||||||
"network.mime.sniff": false,
|
"network.mime.sniff": false,
|
||||||
"session-history.max-length": 20,
|
"session-history.max-length": 20,
|
||||||
"shell.builtin-key-shortcuts.enabled": true,
|
|
||||||
"shell.homepage": "https://servo.org",
|
"shell.homepage": "https://servo.org",
|
||||||
"shell.keep_screen_on.enabled": false,
|
"shell.keep_screen_on.enabled": false,
|
||||||
"shell.native-orientation": "both",
|
"shell.native-orientation": "both",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue