diff --git a/Cargo.lock b/Cargo.lock index 3b9407c176d..3bd64a6ef46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2698,14 +2698,12 @@ dependencies = [ "libservo 0.0.1", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", - "net_traits 0.0.1", "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)", "script_traits 0.0.1", "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo_config 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)", "style_traits 0.0.1", "tinyfiledialogs 3.3.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 2b409b7ae3d..ba31138d5aa 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -34,9 +34,9 @@ use style_traits::viewport::ViewportConstraints; use time::{now, precise_time_ns, precise_time_s}; use touch::{TouchHandler, TouchAction}; 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 windowing::{self, MouseWindowEvent, WebRenderDebugOption, WindowMethods}; +use windowing::{self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods}; #[derive(Debug, PartialEq)] enum UnableToComposite { @@ -110,12 +110,6 @@ pub struct IOCompositor { /// The scene scale, to allow for zooming and high-resolution painting. scale: TypedScale, - /// 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. viewport_zoom: PinchZoomFactor, @@ -126,9 +120,6 @@ pub struct IOCompositor { /// "Desktop-style" zoom that resizes the viewport to fit the window. page_zoom: TypedScale, - /// The device pixel ratio for this window. - scale_factor: TypedScale, - /// The type of composition to perform composite_target: CompositeTarget, @@ -193,6 +184,9 @@ pub struct IOCompositor { /// these frames, it records the paint time for each of them and sends the /// metric to the corresponding layout thread. pending_paint_metrics: HashMap, + + /// The coordinates of the native window, its view and the screen. + embedder_coordinates: EmbedderCoordinates, } #[derive(Clone, Copy)] @@ -350,9 +344,6 @@ impl webrender_api::RenderNotifier for RenderNotifier { impl IOCompositor { fn new(window: Rc, state: InitialCompositorState) -> IOCompositor { - 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 { Some(_) => CompositeTarget::PngFile, None => CompositeTarget::Window @@ -360,14 +351,12 @@ impl IOCompositor { IOCompositor { gl: window.gl(), + embedder_coordinates: window.get_coordinates(), window: window, port: state.receiver, root_pipeline: None, pipeline_details: HashMap::new(), - frame_size: frame_size, - window_rect: window_rect, scale: TypedScale::new(1.0), - scale_factor: scale_factor, composition_request: CompositionRequest::NoCompositingNecessary, touch_handler: TouchHandler::new(), pending_scroll_zoom_events: Vec::new(), @@ -548,6 +537,24 @@ impl IOCompositor { 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 // such as Paint that may crash because we have begun tearing down // the rest of our resources. @@ -634,14 +641,14 @@ impl IOCompositor { } 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.frame_size, - self.window_rect, - self.hidpi_factor().get()); + self.embedder_coordinates.framebuffer, + self.embedder_coordinates.viewport, + 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 { device_pixel_ratio: dppx, @@ -662,24 +669,19 @@ impl IOCompositor { pub fn on_resize_window_event(&mut self) { 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. - let new_scale_factor = self.window.hidpi_factor(); - if self.scale_factor != new_scale_factor { - self.scale_factor = new_scale_factor; + if self.embedder_coordinates.hidpi_factor != old_coords.hidpi_factor { self.update_zoom_transform(); } - let new_window_rect = self.window.window_rect(); - let new_frame_size = self.window.framebuffer_size(); - - if self.window_rect == new_window_rect && - self.frame_size == new_frame_size { + if self.embedder_coordinates.viewport == old_coords.viewport && + self.embedder_coordinates.framebuffer == old_coords.framebuffer { return; } - self.frame_size = new_frame_size; - self.window_rect = new_window_rect; - self.send_window_size(WindowSizeType::Resize); } @@ -1096,7 +1098,7 @@ impl IOCompositor { Some(device_pixels_per_px) => TypedScale::new(device_pixels_per_px), None => match opts::get().output_file { Some(_) => TypedScale::new(1.0), - None => self.scale_factor + None => self.embedder_coordinates.hidpi_factor, } } } @@ -1256,7 +1258,8 @@ impl IOCompositor { fn composite_specific_target(&mut self, target: CompositeTarget) -> Result, 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) { return Err(UnableToComposite::WindowUnprepared) } @@ -1291,7 +1294,7 @@ impl IOCompositor { // Paint the scene. // 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 diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index d93c2c4a2bd..3f43c2ba2bb 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -121,13 +121,6 @@ pub enum EmbedderMsg { MoveTo(TopLevelBrowsingContextId, DeviceIntPoint), /// Resize the window to size 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 AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender), /// Sends an unconsumed key event back to the embedder. @@ -148,6 +141,8 @@ pub enum EmbedderMsg { LoadComplete(TopLevelBrowsingContextId), /// A pipeline panicked. First string is the reason, second one is the backtrace. Panic(TopLevelBrowsingContextId, String, Option), + /// Servo has shut down + Shutdown, } /// 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 LoadComplete(TopLevelBrowsingContextId), + /// Get Window Informations size and position. + GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>), + /// Get screen size. + GetScreenSize(IpcSender), + /// Get screen available size. + GetScreenAvailSize(IpcSender), } impl Debug for Msg { @@ -216,6 +217,9 @@ impl Debug for Msg { Msg::Dispatch(..) => write!(f, "Dispatch"), Msg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"), 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::MoveTo(..) => write!(f, "MoveTo"), 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::KeyEvent(..) => write!(f, "KeyEvent"), EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), @@ -240,6 +241,7 @@ impl Debug for EmbedderMsg { EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"), EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"), EmbedderMsg::Panic(..) => write!(f, "Panic"), + EmbedderMsg::Shutdown => write!(f, "Shutdown"), } } } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index a1fb50d4626..4bfe455ab5b 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -9,14 +9,12 @@ use euclid::TypedScale; use gleam::gl; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection}; -use net_traits::net_error_list::NetError; -use script_traits::{LoadData, MouseButton, TouchEventType, TouchId}; +use script_traits::{MouseButton, TouchEventType, TouchId}; use servo_geometry::{DeviceIndependentPixel, DeviceUintLength}; use servo_url::ServoUrl; use std::fmt::{Debug, Error, Formatter}; use std::rc::Rc; use style_traits::DevicePixel; -use style_traits::cursor::CursorKind; use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintSize, DeviceUintRect, ScrollLocation}; #[derive(Clone)] @@ -121,75 +119,39 @@ pub enum AnimationState { } 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). 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); - /// Called when the browser chrome should display a status message. - fn status(&self, ctx: TopLevelBrowsingContextId, Option); - /// 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); - /// Called when the tag has finished parsing - fn head_parsed(&self, ctx: TopLevelBrowsingContextId); - /// Called when the history state has changed. - fn history_changed(&self, ctx: TopLevelBrowsingContextId, Vec, usize); - - /// Returns the scale factor of the system (device pixels / device independent pixels). - fn hidpi_factor(&self) -> TypedScale; - - /// Returns a thread-safe object to wake up the window's event loop. - fn create_event_loop_waker(&self) -> Box; - /// 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 /// proceed and false if it should not. 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, ch: Option, 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. fn gl(&self) -> Rc; - + /// Returns a thread-safe object to wake up the window's event loop. + fn create_event_loop_waker(&self) -> Box; + /// 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. /// Typically, when animations are active, the window /// will want to avoid blocking on UI events, and just /// run the event loop at the vsync interval. - fn set_animation_state(&self, _state: AnimationState) {} - - /// Called when a pipeline panics. - fn handle_panic(&self, browser_id: TopLevelBrowsingContextId, reason: String, backtrace: Option); + fn set_animation_state(&self, _state: AnimationState); +} + +#[derive(Clone, Copy, Debug)] +pub struct EmbedderCoordinates { + /// The pixel density of the display. + pub hidpi_factor: TypedScale, + /// 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, } diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index cdc850495b1..738d992b840 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1229,9 +1229,6 @@ impl Constellation debug!("constellation got Alert message"); 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) => { self.embedder_proxy.send(EmbedderMsg::MoveTo(source_top_ctx_id, point)); @@ -1241,12 +1238,14 @@ impl Constellation self.embedder_proxy.send(EmbedderMsg::ResizeTo(source_top_ctx_id, size)); } - FromScriptMsg::GetScreenSize(send) => { - self.embedder_proxy.send(EmbedderMsg::GetScreenSize(source_top_ctx_id, send)); + FromScriptMsg::GetClientWindow(send) => { + self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send)); + } + FromScriptMsg::GetScreenSize(send) => { + self.compositor_proxy.send(ToCompositorMsg::GetScreenSize(send)); } - FromScriptMsg::GetScreenAvailSize(send) => { - self.embedder_proxy.send(EmbedderMsg::GetScreenAvailSize(source_top_ctx_id, send)); + self.compositor_proxy.send(ToCompositorMsg::GetScreenAvailSize(send)); } FromScriptMsg::Exit => { diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 153adbd98fe..6173f83a495 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -136,8 +136,6 @@ pub enum ScriptMsg { SetTitle(Option), /// Send a key event SendKeyEvent(Option, Key, KeyState, KeyModifiers), - /// Get Window Informations size and position - GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>), /// Move the window to a point MoveTo(DeviceIntPoint), /// Resize the window to size @@ -155,6 +153,8 @@ pub enum ScriptMsg { RegisterServiceWorker(ScopeThings, ServoUrl), /// Enter or exit fullscreen SetFullscreenState(bool), + /// Get Window Informations size and position + GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>), /// Get the screen size (pixel) GetScreenSize(IpcSender<(DeviceUintSize)>), /// Get the available screen size (pixel) diff --git a/components/servo/lib.rs b/components/servo/lib.rs index bc1a7f6a8f1..d557cb3e591 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -74,8 +74,7 @@ use canvas::webgl_thread::WebGLThreads; use compositing::{IOCompositor, ShutdownState, RenderNotifier}; use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState}; use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver}; -use compositing::windowing::WindowEvent; -use compositing::windowing::WindowMethods; +use compositing::windowing::{WindowEvent, WindowMethods}; use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent}; use constellation::{FromCompositorLogger, FromScriptLogger}; #[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 ipc_channel::ipc::{self, IpcSender}; use log::{Log, LogMetadata, LogRecord}; -use msg::constellation_msg::KeyState; use net::resource_thread::new_resource_threads; use net_traits::IpcSend; use profile::mem as profile_mem; @@ -109,7 +107,7 @@ use webvr::{WebVRThread, WebVRCompositorHandler}; pub use gleam::gl; pub use servo_config as config; 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. /// @@ -125,7 +123,8 @@ pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; pub struct Servo { compositor: IOCompositor, constellation_chan: Sender, - embedder_receiver: EmbedderReceiver + embedder_receiver: EmbedderReceiver, + embedder_events: Vec, } impl Servo where Window: WindowMethods + 'static { @@ -158,17 +157,9 @@ impl Servo where Window: WindowMethods + 'static { let mut resource_path = resources_dir_path().unwrap(); resource_path.push("shaders"); - let (mut webrender, webrender_api_sender) = { - // 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 coordinates = window.get_coordinates(); + let (mut webrender, webrender_api_sender) = { let renderer_kind = if opts::get().should_use_osmesa() { RendererKind::OSMesa } else { @@ -189,7 +180,7 @@ impl Servo where Window: WindowMethods + 'static { let render_notifier = Box::new(RenderNotifier::new(compositor_proxy.clone())); 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), enable_aa: opts.enable_text_antialiasing, debug_flags: debug_flags, @@ -205,7 +196,7 @@ impl Servo where Window: WindowMethods + 'static { let webrender_api = webrender_api_sender.create_api(); 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 // can't defer it after `create_constellation` has started. @@ -254,6 +245,7 @@ impl Servo where Window: WindowMethods + 'static { compositor: compositor, constellation_chan: constellation_chan, embedder_receiver: embedder_receiver, + embedder_events: Vec::new(), } } @@ -370,108 +362,26 @@ impl Servo where Window: WindowMethods + 'static { (_, ShutdownState::ShuttingDown) => {}, - (EmbedderMsg::Status(top_level_browsing_context, message), ShutdownState::NotShuttingDown) => { - 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), + (EmbedderMsg::KeyEvent(top_level_browsing_context, ch, key, state, modified), ShutdownState::NotShuttingDown) => { 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) => { - self.compositor.window.set_cursor(cursor) + (msg, ShutdownState::NotShuttingDown) => { + 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) -> bool { + pub fn get_events(&mut self) -> Vec { + ::std::mem::replace(&mut self.embedder_events, Vec::new()) + } + + pub fn handle_events(&mut self, events: Vec) { if self.compositor.receive_messages() { self.receive_messages(); } @@ -480,8 +390,9 @@ impl Servo where Window: WindowMethods + 'static { } if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown { self.compositor.perform_updates(); + } else { + self.embedder_events.push(EmbedderMsg::Shutdown); } - self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown } pub fn repaint_synchronously(&mut self) { diff --git a/ports/servo/Cargo.toml b/ports/servo/Cargo.toml index e156fabe37b..4f42def7c53 100644 --- a/ports/servo/Cargo.toml +++ b/ports/servo/Cargo.toml @@ -43,11 +43,9 @@ glutin = "0.13" libservo = {path = "../../components/servo"} log = "0.3.5" msg = {path = "../../components/msg"} -net_traits = {path = "../../components/net_traits"} script_traits = {path = "../../components/script_traits"} servo_geometry = {path = "../../components/geometry"} servo_config = {path = "../../components/config"} -servo_url = {path = "../../components/url"} style_traits = {path = "../../components/style_traits"} tinyfiledialogs = "3.0" webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/ports/servo/browser.rs b/ports/servo/browser.rs new file mode 100644 index 00000000000..0231cb131b7 --- /dev/null +++ b/ports/servo/browser.rs @@ -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, + /// id of the top level browsing context. It is unique as tabs + /// are not supported yet. None until created. + browser_id: Option, + + title: Option, + status: Option, + favicon: Option, + loading_state: Option, + window: Rc, + event_queue: Vec, + shutdown_requested: bool, +} + +enum LoadingState { + Connecting, + Loading, + Loaded, +} + +impl Browser { + pub fn new(window: Rc) -> 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 { + 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) { + 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, 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 { + 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 { + None + } + + /// Handle key events after they have been handled by Servo. + fn handle_key_from_servo(&mut self, _: Option, ch: Option, + 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) { + 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 { + 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() + }) + }) +} diff --git a/ports/servo/glutin_app/keyutils.rs b/ports/servo/glutin_app/keyutils.rs new file mode 100644 index 00000000000..bce62893cde --- /dev/null +++ b/ports/servo/glutin_app/keyutils.rs @@ -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 { + 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 { + // 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 + } +} diff --git a/ports/servo/glutin_app/mod.rs b/ports/servo/glutin_app/mod.rs index 5ea843f1911..a7e8ac8f5e8 100644 --- a/ports/servo/glutin_app/mod.rs +++ b/ports/servo/glutin_app/mod.rs @@ -4,6 +4,7 @@ //! A simple application that uses glutin to open a window for Servo to display in. +pub mod keyutils; pub mod window; use servo_config::opts; diff --git a/ports/servo/glutin_app/window.rs b/ports/servo/glutin_app/window.rs index f37bcf701a6..624ed0d5f1f 100644 --- a/ports/servo/glutin_app/window.rs +++ b/ports/servo/glutin_app/window.rs @@ -6,25 +6,18 @@ use compositing::compositor_thread::EventLoopWaker; use compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent}; -use compositing::windowing::{WebRenderDebugOption, WindowMethods}; +use compositing::windowing::{EmbedderCoordinates, WindowMethods}; use euclid::{Length, TypedPoint2D, TypedVector2D, TypedScale, TypedSize2D}; #[cfg(target_os = "windows")] use gdi32; use gleam::gl; -use glutin; -use glutin::{Api, GlContext, GlRequest}; -use msg::constellation_msg::{self, Key, TopLevelBrowsingContextId as BrowserId}; -use msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection}; -use net_traits::net_error_list::NetError; -use net_traits::pub_domains::is_reg_domain; +use glutin::{self, Api, GlContext, GlRequest}; +use msg::constellation_msg::{Key, KeyState}; #[cfg(any(target_os = "linux", target_os = "macos"))] use osmesa_sys; -use script_traits::{LoadData, TouchEventType}; -use servo::ipc_channel::ipc::IpcSender; +use script_traits::TouchEventType; use servo_config::opts; -use servo_config::prefs::PREFS; use servo_geometry::DeviceIndependentPixel; -use servo_url::ServoUrl; use std::cell::{Cell, RefCell}; #[cfg(any(target_os = "linux", target_os = "macos"))] use std::ffi::CString; @@ -37,7 +30,7 @@ use std::thread; use std::time; use style_traits::DevicePixel; use style_traits::cursor::CursorKind; -use tinyfiledialogs; +use super::keyutils::{self, GlutinKeyModifiers}; #[cfg(target_os = "windows")] use user32; use webrender_api::{DeviceIntPoint, DeviceUintRect, DeviceUintSize, ScrollLocation}; @@ -49,33 +42,8 @@ use winit::{ElementState, Event, MouseButton, MouseScrollDelta, TouchPhase, Virt use winit::os::macos::{ActivationPolicy, WindowBuilderExt}; -bitflags! { - 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")] -const CMD_OR_CONTROL: KeyModifiers = KeyModifiers::SUPER; -#[cfg(not(target_os = "macos"))] -const CMD_OR_CONTROL: KeyModifiers = KeyModifiers::CONTROL; - -// Some shortcuts use Cmd on Mac and Alt on other systems. -#[cfg(target_os = "macos")] -const CMD_OR_ALT: KeyModifiers = KeyModifiers::SUPER; -#[cfg(not(target_os = "macos"))] -const CMD_OR_ALT: KeyModifiers = KeyModifiers::ALT; - // This should vary by zoom level and maybe actual text size (focused or under cursor) -const LINE_HEIGHT: f32 = 38.0; +pub const LINE_HEIGHT: f32 = 38.0; const MULTISAMPLES: u16 = 16; @@ -179,25 +147,14 @@ pub struct Window { kind: WindowKind, screen_size: TypedSize2D, inner_size: Cell>, - mouse_down_button: Cell>, mouse_down_point: Cell>, event_queue: RefCell>, - - /// id of the top level browsing context. It is unique as tabs - /// are not supported yet. None until created. - browser_id: Cell>, - mouse_pos: Cell>, key_modifiers: Cell, - current_url: RefCell>, - - last_pressed_key: Cell>, - + last_pressed_key: Cell>, animation_state: Cell, - fullscreen: Cell, - gl: Rc, suspended: Cell, } @@ -216,10 +173,6 @@ fn window_creation_scale_factor() -> TypedScale) -> Rc { let win_size: DeviceUintSize = (window_size.to_f32() * window_creation_scale_factor()).to_u32(); @@ -316,11 +269,8 @@ impl Window { mouse_down_button: Cell::new(None), mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)), - browser_id: Cell::new(None), - mouse_pos: Cell::new(TypedPoint2D::new(0, 0)), key_modifiers: Cell::new(GlutinKeyModifiers::empty()), - current_url: RefCell::new(None), last_pressed_key: Cell::new(None), gl: gl.clone(), @@ -336,6 +286,107 @@ impl Window { Rc::new(window) } + pub fn get_events(&self) -> Vec { + mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new()) + } + + pub fn page_height(&self) -> f32 { + let dpr = self.hidpi_factor(); + match self.kind { + WindowKind::Window(ref window, _) => { + let (_, height) = window.get_inner_size().expect("Failed to get window inner size."); + height as f32 * dpr.get() + }, + WindowKind::Headless(ref context) => { + context.height as f32 * dpr.get() + } + } + } + + pub fn set_title(&self, title: &str) { + if let WindowKind::Window(ref window, _) = self.kind { + window.set_title(title); + } + } + + pub fn set_inner_size(&self, size: DeviceUintSize) { + if let WindowKind::Window(ref window, _) = self.kind { + let size = size.to_f32() / self.hidpi_factor(); + window.set_inner_size(size.width as u32, size.height as u32) + } + } + + pub fn set_position(&self, point: DeviceIntPoint) { + if let WindowKind::Window(ref window, _) = self.kind { + let point = point.to_f32() / self.hidpi_factor(); + window.set_position(point.x as i32, point.y as i32) + } + } + + pub fn set_fullscreen(&self, state: bool) { + match self.kind { + WindowKind::Window(ref window, ..) => { + if self.fullscreen.get() != state { + window.set_fullscreen(None); + } + }, + WindowKind::Headless(..) => {} + } + self.fullscreen.set(state); + } + + fn is_animating(&self) -> bool { + self.animation_state.get() == AnimationState::Animating && !self.suspended.get() + } + + pub fn run(&self, mut servo_callback: T) where T: FnMut() -> bool { + match self.kind { + WindowKind::Window(_, ref events_loop) => { + let mut stop = false; + loop { + if self.is_animating() { + // We block on compositing (servo_callback ends up calling swap_buffers) + events_loop.borrow_mut().poll_events(|e| { + self.glutin_event_to_servo_event(e); + }); + stop = servo_callback(); + } else { + // We block on glutin's event loop (window events) + events_loop.borrow_mut().run_forever(|e| { + self.glutin_event_to_servo_event(e); + if !self.event_queue.borrow().is_empty() { + if !self.suspended.get() { + stop = servo_callback(); + } + } + if stop || self.is_animating() { + winit::ControlFlow::Break + } else { + winit::ControlFlow::Continue + } + }); + } + if stop { + break; + } + } + } + WindowKind::Headless(..) => { + loop { + // Sleep the main thread to avoid using 100% CPU + // This can be done better, see comments in #18777 + if self.event_queue.borrow().is_empty() { + thread::sleep(time::Duration::from_millis(5)); + } + let stop = servo_callback(); + if stop { + break; + } + } + } + } + } + #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] fn gl_version() -> GlRequest { return GlRequest::Specific(Api::OpenGl, (3, 2)); @@ -346,30 +397,9 @@ impl Window { GlRequest::Specific(Api::OpenGlEs, (3, 0)) } - /// Detect if given char is default ignorable in unicode - /// http://www.unicode.org/L2/L2002/02368-default-ignorable.pdf - fn is_identifier_ignorable(&self, 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 - } - } - fn handle_received_character(&self, ch: char) { - let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get()); - if self.is_identifier_ignorable(&ch) { + let modifiers = keyutils::glutin_mods_to_script_mods(self.key_modifiers.get()); + if keyutils::is_identifier_ignorable(&ch) { return } if let Some(last_pressed_key) = self.last_pressed_key.get() { @@ -378,7 +408,7 @@ impl Window { } else { // Only send the character if we can print it (by ignoring characters like backspace) if !ch.is_control() { - match Window::char_to_script_key(ch) { + match keyutils::char_to_script_key(ch) { Some(key) => { let event = WindowEvent::KeyEvent(Some(ch), key, @@ -410,22 +440,22 @@ impl Window { fn handle_keyboard_input(&self, element_state: ElementState, virtual_key_code: VirtualKeyCode) { self.toggle_keyboard_modifiers(virtual_key_code); - if let Ok(key) = Window::glutin_key_to_script_key(virtual_key_code) { + if let Ok(key) = keyutils::glutin_key_to_script_key(virtual_key_code) { let state = match element_state { ElementState::Pressed => KeyState::Pressed, ElementState::Released => KeyState::Released, }; if element_state == ElementState::Pressed { - if is_printable(virtual_key_code) { + if keyutils::is_printable(virtual_key_code) { self.last_pressed_key.set(Some(key)); } } - let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get()); + let modifiers = keyutils::glutin_mods_to_script_mods(self.key_modifiers.get()); self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(None, key, state, modifiers)); } } - fn handle_window_event(&self, event: winit::Event) { + fn glutin_event_to_servo_event(&self, event: winit::Event) { match event { Event::WindowEvent { event: winit::WindowEvent::ReceivedCharacter(ch), @@ -462,13 +492,22 @@ impl Window { event: winit::WindowEvent::MouseWheel { delta, phase, .. }, .. } => { - let (dx, dy) = match delta { + let (mut dx, mut dy) = match delta { MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT), MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy), }; + // Scroll events snap to the major axis of movement, with vertical + // preferred over horizontal. + if dy.abs() >= dx.abs() { + dx = 0.0; + } else { + dy = 0.0; + } + let scroll_location = ScrollLocation::Delta(TypedVector2D::new(dx, dy)); let phase = glutin_phase_to_touch_event_type(phase); - self.scroll_window(scroll_location, phase); + let event = WindowEvent::Scroll(scroll_location, self.mouse_pos.get(), phase); + self.event_queue.borrow_mut().push(event); }, Event::WindowEvent { event: winit::WindowEvent::Touch(touch), @@ -527,22 +566,6 @@ impl Window { self.key_modifiers.set(modifiers); } - /// Helper function to send a scroll event. - fn scroll_window(&self, mut scroll_location: ScrollLocation, phase: TouchEventType) { - // Scroll events snap to the major axis of movement, with vertical - // preferred over horizontal. - if let ScrollLocation::Delta(ref mut delta) = scroll_location { - if delta.y.abs() >= delta.x.abs() { - delta.x = 0.0; - } else { - delta.y = 0.0; - } - } - - let event = WindowEvent::Scroll(scroll_location, self.mouse_pos.get(), phase); - self.event_queue.borrow_mut().push(event); - } - /// Helper function to handle a click fn handle_mouse(&self, button: winit::MouseButton, action: winit::ElementState, @@ -578,309 +601,84 @@ impl Window { self.event_queue.borrow_mut().push(WindowEvent::MouseWindowEventClass(event)); } - pub fn get_events(&self) -> Vec { - mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new()) + fn hidpi_factor(&self) -> TypedScale { + match opts::get().device_pixels_per_px { + Some(device_pixels_per_px) => TypedScale::new(device_pixels_per_px), + None => match opts::get().output_file { + Some(_) => TypedScale::new(1.0), + None => self.platform_hidpi_factor() + } + } } - fn is_animating(&self) -> bool { - self.animation_state.get() == AnimationState::Animating && !self.suspended.get() - } - - pub fn run(&self, mut servo_callback: T) where T: FnMut() -> bool { + #[cfg(not(target_os = "windows"))] + fn platform_hidpi_factor(&self) -> TypedScale { match self.kind { - WindowKind::Window(_, ref events_loop) => { - let mut stop = false; - loop { - if self.is_animating() { - // We block on compositing (servo_callback ends up calling swap_buffers) - events_loop.borrow_mut().poll_events(|e| { - self.handle_window_event(e); - }); - stop = servo_callback(); - } else { - // We block on glutin's event loop (window events) - events_loop.borrow_mut().run_forever(|e| { - self.handle_window_event(e); - if !self.event_queue.borrow().is_empty() { - if !self.suspended.get() { - stop = servo_callback(); - } - } - if stop || self.is_animating() { - winit::ControlFlow::Break - } else { - winit::ControlFlow::Continue - } - }); - } - if stop { - break; - } - } + WindowKind::Window(ref window, ..) => { + TypedScale::new(window.hidpi_factor()) } WindowKind::Headless(..) => { - loop { - // Sleep the main thread to avoid using 100% CPU - // This can be done better, see comments in #18777 - if self.event_queue.borrow().is_empty() { - thread::sleep(time::Duration::from_millis(5)); - } - let stop = servo_callback(); - if stop { - break; - } - } + TypedScale::new(1.0) } } } - fn char_to_script_key(c: char) -> Option { - 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 - } + #[cfg(target_os = "windows")] + fn platform_hidpi_factor(&self) -> TypedScale { + let hdc = unsafe { user32::GetDC(::std::ptr::null_mut()) }; + let ppi = unsafe { gdi32::GetDeviceCaps(hdc, winapi::wingdi::LOGPIXELSY) }; + TypedScale::new(ppi as f32 / 96.0) } - fn glutin_key_to_script_key(key: winit::VirtualKeyCode) -> Result { - // 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), + /// Has no effect on Android. + pub fn set_cursor(&self, cursor: CursorKind) { + match self.kind { + WindowKind::Window(ref window, ..) => { + use winit::MouseCursor; - 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(()), - } - } - - 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 - } - - #[cfg(not(target_os = "win"))] - fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers, browser_id: BrowserId) { - match (mods, key) { - (CMD_OR_CONTROL, Key::LeftBracket) => { - let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1)); - self.event_queue.borrow_mut().push(event); + let glutin_cursor = match cursor { + CursorKind::Auto => MouseCursor::Default, + CursorKind::None => MouseCursor::NoneCursor, + CursorKind::Default => MouseCursor::Default, + CursorKind::Pointer => MouseCursor::Hand, + CursorKind::ContextMenu => MouseCursor::ContextMenu, + CursorKind::Help => MouseCursor::Help, + CursorKind::Progress => MouseCursor::Progress, + CursorKind::Wait => MouseCursor::Wait, + CursorKind::Cell => MouseCursor::Cell, + CursorKind::Crosshair => MouseCursor::Crosshair, + CursorKind::Text => MouseCursor::Text, + CursorKind::VerticalText => MouseCursor::VerticalText, + CursorKind::Alias => MouseCursor::Alias, + CursorKind::Copy => MouseCursor::Copy, + CursorKind::Move => MouseCursor::Move, + CursorKind::NoDrop => MouseCursor::NoDrop, + CursorKind::NotAllowed => MouseCursor::NotAllowed, + CursorKind::Grab => MouseCursor::Grab, + CursorKind::Grabbing => MouseCursor::Grabbing, + CursorKind::EResize => MouseCursor::EResize, + CursorKind::NResize => MouseCursor::NResize, + CursorKind::NeResize => MouseCursor::NeResize, + CursorKind::NwResize => MouseCursor::NwResize, + CursorKind::SResize => MouseCursor::SResize, + CursorKind::SeResize => MouseCursor::SeResize, + CursorKind::SwResize => MouseCursor::SwResize, + CursorKind::WResize => MouseCursor::WResize, + CursorKind::EwResize => MouseCursor::EwResize, + CursorKind::NsResize => MouseCursor::NsResize, + CursorKind::NeswResize => MouseCursor::NeswResize, + CursorKind::NwseResize => MouseCursor::NwseResize, + CursorKind::ColResize => MouseCursor::ColResize, + CursorKind::RowResize => MouseCursor::RowResize, + CursorKind::AllScroll => MouseCursor::AllScroll, + CursorKind::ZoomIn => MouseCursor::ZoomIn, + CursorKind::ZoomOut => MouseCursor::ZoomOut, + }; + window.set_cursor(glutin_cursor); } - (CMD_OR_CONTROL, Key::RightBracket) => { - let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1)); - self.event_queue.borrow_mut().push(event); - } - _ => {} + WindowKind::Headless(..) => {} } } - - #[cfg(target_os = "win")] - fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers, browser_id: BrowserId) { - } } impl WindowMethods for Window { @@ -888,80 +686,44 @@ impl WindowMethods for Window { self.gl.clone() } - fn framebuffer_size(&self) -> DeviceUintSize { - (self.inner_size.get().to_f32() * self.hidpi_factor()).to_u32() - } - - fn window_rect(&self) -> DeviceUintRect { - let size = self.framebuffer_size(); - let origin = TypedPoint2D::zero(); - DeviceUintRect::new(origin, size) - } - - fn client_window(&self, _: BrowserId) -> (DeviceUintSize, DeviceIntPoint) { - let (size, point) = match self.kind { - WindowKind::Window(ref window, ..) => { + fn get_coordinates(&self) -> EmbedderCoordinates { + let dpr = self.hidpi_factor(); + match self.kind { + WindowKind::Window(ref window, _) => { // TODO(ajeffrey): can this fail? let (width, height) = window.get_outer_size().expect("Failed to get window outer size."); - let size = TypedSize2D::new(width as f32, height as f32); - // TODO(ajeffrey): can this fail? - let (x, y) = window.get_position().expect("Failed to get window position."); - let origin = TypedPoint2D::new(x as f32, y as f32); - (size, origin) - } - WindowKind::Headless(ref context) => { - let size = TypedSize2D::new(context.width as f32, context.height as f32); - let origin = TypedPoint2D::zero(); - (size, origin) - } - }; - let dpr = self.hidpi_factor(); - ((size * dpr).to_u32(), (point * dpr).to_i32()) - } + let (x, y) = window.get_position().unwrap_or((0, 0)); + let win_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_u32(); + let win_origin = (TypedPoint2D::new(x as f32, y as f32) * dpr).to_i32(); + let screen = (self.screen_size.to_f32() * dpr).to_u32(); - fn screen_size(&self, _: BrowserId) -> DeviceUintSize { - (self.screen_size.to_f32() * self.hidpi_factor()).to_u32() - } + let (width, height) = window.get_inner_size().expect("Failed to get window inner size."); + let inner_size = (TypedSize2D::new(width as f32, height as f32) * dpr).to_u32(); - fn screen_avail_size(&self, browser_id: BrowserId) -> DeviceUintSize { - // FIXME: Glutin doesn't have API for available size. Fallback to screen size - self.screen_size(browser_id) - } + let viewport = DeviceUintRect::new(TypedPoint2D::zero(), inner_size); - fn set_animation_state(&self, state: AnimationState) { - self.animation_state.set(state); - } - - fn set_inner_size(&self, _: BrowserId, size: DeviceUintSize) { - match self.kind { - WindowKind::Window(ref window, ..) => { - let size = size.to_f32() / self.hidpi_factor(); - window.set_inner_size(size.width as u32, size.height as u32) - } - WindowKind::Headless(..) => {} - } - } - - fn set_position(&self, _: BrowserId, point: DeviceIntPoint) { - match self.kind { - WindowKind::Window(ref window, ..) => { - let point = point.to_f32() / self.hidpi_factor(); - window.set_position(point.x as i32, point.y as i32) - } - WindowKind::Headless(..) => {} - } - } - - fn set_fullscreen_state(&self, _: BrowserId, state: bool) { - match self.kind { - WindowKind::Window(ref window, ..) => { - if self.fullscreen.get() != state { - window.set_fullscreen(None); + EmbedderCoordinates { + viewport: viewport, + framebuffer: inner_size, + window: (win_size, win_origin), + screen: screen, + // FIXME: Glutin doesn't have API for available size. Fallback to screen size + screen_avail: screen, + hidpi_factor: dpr, } }, - WindowKind::Headless(..) => {} + WindowKind::Headless(ref context) => { + let size = (TypedSize2D::new(context.width, context.height).to_f32() * dpr).to_u32(); + EmbedderCoordinates { + viewport: DeviceUintRect::new(TypedPoint2D::zero(), size), + framebuffer: size, + window: (size, TypedPoint2D::zero()), + screen: size, + screen_avail: size, + hidpi_factor: dpr, + } + } } - self.fullscreen.set(state); } fn present(&self) { @@ -1011,278 +773,17 @@ impl WindowMethods for Window { Box::new(GlutinEventLoopWaker::new(&self)) } - #[cfg(not(target_os = "windows"))] - fn hidpi_factor(&self) -> TypedScale { - match self.kind { - WindowKind::Window(ref window, ..) => { - TypedScale::new(window.hidpi_factor()) - } - WindowKind::Headless(..) => { - TypedScale::new(1.0) - } - } - } - - #[cfg(target_os = "windows")] - fn hidpi_factor(&self) -> TypedScale { - let hdc = unsafe { user32::GetDC(::std::ptr::null_mut()) }; - let ppi = unsafe { gdi32::GetDeviceCaps(hdc, winapi::wingdi::LOGPIXELSY) }; - TypedScale::new(ppi as f32 / 96.0) - } - - fn set_page_title(&self, _: BrowserId, title: Option) { - match self.kind { - WindowKind::Window(ref window, ..) => { - let fallback_title: String = if let Some(ref current_url) = *self.current_url.borrow() { - current_url.to_string() - } else { - String::from("Untitled") - }; - - let title = match title { - Some(ref title) if title.len() > 0 => &**title, - _ => &fallback_title, - }; - let title = format!("{} - Servo", title); - window.set_title(&title); - } - WindowKind::Headless(..) => {} - } - } - - fn status(&self, _: BrowserId, _: Option) { - } - - fn load_start(&self, _: BrowserId) { - } - - fn load_end(&self, _: BrowserId) { - if opts::get().no_native_titlebar { - match self.kind { - WindowKind::Window(ref window, ..) => { - window.show(); - } - WindowKind::Headless(..) => {} - } - } - } - - fn history_changed(&self, _: BrowserId, history: Vec, current: usize) { - *self.current_url.borrow_mut() = Some(history[current].url.clone()); - } - - fn load_error(&self, _: BrowserId, _: NetError, _: String) { - } - - fn head_parsed(&self, _: BrowserId) { - } - - /// Has no effect on Android. - fn set_cursor(&self, cursor: CursorKind) { - match self.kind { - WindowKind::Window(ref window, ..) => { - use winit::MouseCursor; - - let glutin_cursor = match cursor { - CursorKind::Auto => MouseCursor::Default, - CursorKind::None => MouseCursor::NoneCursor, - CursorKind::Default => MouseCursor::Default, - CursorKind::Pointer => MouseCursor::Hand, - CursorKind::ContextMenu => MouseCursor::ContextMenu, - CursorKind::Help => MouseCursor::Help, - CursorKind::Progress => MouseCursor::Progress, - CursorKind::Wait => MouseCursor::Wait, - CursorKind::Cell => MouseCursor::Cell, - CursorKind::Crosshair => MouseCursor::Crosshair, - CursorKind::Text => MouseCursor::Text, - CursorKind::VerticalText => MouseCursor::VerticalText, - CursorKind::Alias => MouseCursor::Alias, - CursorKind::Copy => MouseCursor::Copy, - CursorKind::Move => MouseCursor::Move, - CursorKind::NoDrop => MouseCursor::NoDrop, - CursorKind::NotAllowed => MouseCursor::NotAllowed, - CursorKind::Grab => MouseCursor::Grab, - CursorKind::Grabbing => MouseCursor::Grabbing, - CursorKind::EResize => MouseCursor::EResize, - CursorKind::NResize => MouseCursor::NResize, - CursorKind::NeResize => MouseCursor::NeResize, - CursorKind::NwResize => MouseCursor::NwResize, - CursorKind::SResize => MouseCursor::SResize, - CursorKind::SeResize => MouseCursor::SeResize, - CursorKind::SwResize => MouseCursor::SwResize, - CursorKind::WResize => MouseCursor::WResize, - CursorKind::EwResize => MouseCursor::EwResize, - CursorKind::NsResize => MouseCursor::NsResize, - CursorKind::NeswResize => MouseCursor::NeswResize, - CursorKind::NwseResize => MouseCursor::NwseResize, - CursorKind::ColResize => MouseCursor::ColResize, - CursorKind::RowResize => MouseCursor::RowResize, - CursorKind::AllScroll => MouseCursor::AllScroll, - CursorKind::ZoomIn => MouseCursor::ZoomIn, - CursorKind::ZoomOut => MouseCursor::ZoomOut, - }; - window.set_cursor(glutin_cursor); - } - WindowKind::Headless(..) => {} - } - } - - fn set_favicon(&self, _: BrowserId, _: ServoUrl) { + fn set_animation_state(&self, state: AnimationState) { + self.animation_state.set(state); } fn prepare_for_composite(&self, _width: Length, _height: Length) -> bool { true } - /// Helper function to handle keyboard events. - fn handle_key(&self, _: Option, ch: Option, key: Key, mods: constellation_msg::KeyModifiers) { - let browser_id = match self.browser_id.get() { - Some(id) => id, - None => { unreachable!("Can't get keys without a browser"); } - }; - match (mods, ch, key) { - (_, Some('+'), _) => { - if mods & !KeyModifiers::SHIFT == CMD_OR_CONTROL { - self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1)); - } else if mods & !KeyModifiers::SHIFT == CMD_OR_CONTROL | KeyModifiers::ALT { - self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.1)); - } - } - (CMD_OR_CONTROL, Some('-'), _) => { - self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.0 / 1.1)); - } - (_, Some('-'), _) if mods == CMD_OR_CONTROL | KeyModifiers::ALT => { - self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.0 / 1.1)); - } - (CMD_OR_CONTROL, Some('0'), _) => { - self.event_queue.borrow_mut().push(WindowEvent::ResetZoom); - } - - (KeyModifiers::NONE, None, Key::NavigateForward) => { - let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1)); - self.event_queue.borrow_mut().push(event); - } - (KeyModifiers::NONE, None, Key::NavigateBackward) => { - let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1)); - self.event_queue.borrow_mut().push(event); - } - - (KeyModifiers::NONE, None, Key::Escape) => { - if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() { - self.event_queue.borrow_mut().push(WindowEvent::Quit); - } - } - - (CMD_OR_ALT, None, Key::Right) => { - let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1)); - self.event_queue.borrow_mut().push(event); - } - (CMD_OR_ALT, None, Key::Left) => { - let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1)); - self.event_queue.borrow_mut().push(event); - } - - (KeyModifiers::NONE, None, Key::PageDown) => { - let scroll_location = ScrollLocation::Delta(TypedVector2D::new(0.0, - -self.framebuffer_size() - .to_f32() - .to_untyped() - .height + 2.0 * LINE_HEIGHT)); - self.scroll_window(scroll_location, - TouchEventType::Move); - } - (KeyModifiers::NONE, None, Key::PageUp) => { - let scroll_location = ScrollLocation::Delta(TypedVector2D::new(0.0, - self.framebuffer_size() - .to_f32() - .to_untyped() - .height - 2.0 * LINE_HEIGHT)); - self.scroll_window(scroll_location, - TouchEventType::Move); - } - - (KeyModifiers::NONE, None, Key::Home) => { - self.scroll_window(ScrollLocation::Start, TouchEventType::Move); - } - - (KeyModifiers::NONE, None, Key::End) => { - self.scroll_window(ScrollLocation::End, TouchEventType::Move); - } - - (KeyModifiers::NONE, None, Key::Up) => { - self.scroll_window(ScrollLocation::Delta(TypedVector2D::new(0.0, 3.0 * LINE_HEIGHT)), - TouchEventType::Move); - } - (KeyModifiers::NONE, None, Key::Down) => { - self.scroll_window(ScrollLocation::Delta(TypedVector2D::new(0.0, -3.0 * LINE_HEIGHT)), - TouchEventType::Move); - } - (KeyModifiers::NONE, None, Key::Left) => { - self.scroll_window(ScrollLocation::Delta(TypedVector2D::new(LINE_HEIGHT, 0.0)), TouchEventType::Move); - } - (KeyModifiers::NONE, None, Key::Right) => { - self.scroll_window(ScrollLocation::Delta(TypedVector2D::new(-LINE_HEIGHT, 0.0)), TouchEventType::Move); - } - (CMD_OR_CONTROL, Some('r'), _) => { - if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() { - self.event_queue.borrow_mut().push(WindowEvent::Reload(browser_id)); - } - } - (CMD_OR_CONTROL, Some('l'), _) => { - if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() { - let url: String = if let Some(ref url) = *self.current_url.borrow() { - 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.borrow_mut().push(WindowEvent::LoadUrl(browser_id, url)); - } - } - } - } - (CMD_OR_CONTROL, Some('q'), _) => { - if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() { - self.event_queue.borrow_mut().push(WindowEvent::Quit); - } - } - (_, Some('3'), _) => if mods ^ KeyModifiers::CONTROL == KeyModifiers::SHIFT { - self.event_queue.borrow_mut().push(WindowEvent::CaptureWebRender); - } - (KeyModifiers::CONTROL, None, Key::F10) => { - let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::RenderTargetDebug); - self.event_queue.borrow_mut().push(event); - } - (KeyModifiers::CONTROL, None, Key::F11) => { - let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::TextureCacheDebug); - self.event_queue.borrow_mut().push(event); - } - (KeyModifiers::CONTROL, None, Key::F12) => { - let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::Profiler); - self.event_queue.borrow_mut().push(event); - } - - _ => { - self.platform_handle_key(key, mods, browser_id); - } - } - } - - fn allow_navigation(&self, _: BrowserId, _: ServoUrl, response_chan: IpcSender) { - if let Err(e) = response_chan.send(true) { - warn!("Failed to send allow_navigation() response: {}", e); - }; - } - fn supports_clipboard(&self) -> bool { true } - - fn handle_panic(&self, _: BrowserId, _reason: String, _backtrace: Option) { - // Nothing to do here yet. The crash has already been reported on the console. - } } fn glutin_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { @@ -1293,91 +794,3 @@ fn glutin_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { TouchPhase::Cancelled => TouchEventType::Cancel, } } - -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, - } -} - -fn sanitize_url(request: &str) -> Option { - 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() - }) - }) -} diff --git a/ports/servo/main.rs b/ports/servo/main.rs index 3c025675877..5401ef9130d 100644 --- a/ports/servo/main.rs +++ b/ports/servo/main.rs @@ -29,13 +29,11 @@ extern crate glutin; // The window backed by glutin #[macro_use] extern crate log; extern crate msg; -extern crate net_traits; #[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys; extern crate script_traits; extern crate servo; extern crate servo_config; extern crate servo_geometry; -extern crate servo_url; #[cfg(all(feature = "unstable", not(target_os = "android")))] #[macro_use] extern crate sig; @@ -63,6 +61,8 @@ use std::panic; use std::process; use std::thread; +mod browser; + pub mod platform { #[cfg(target_os = "macos")] pub use platform::macos::deinit; @@ -163,6 +163,8 @@ fn main() { 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, // or a blank page in case the homepage is not set either. let cwd = env::current_dir().unwrap(); @@ -178,22 +180,40 @@ fn main() { let (sender, receiver) = ipc::channel().unwrap(); servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]); 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.setup_logging(); window.run(|| { - let events = window.get_events(); - let need_resize = events.iter().any(|e| match *e { + let win_events = window.get_events(); + + // 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, - _ => 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 { servo.repaint_synchronously(); } - stop + false }); servo.deinit(); diff --git a/resources/prefs.json b/resources/prefs.json index 5d21c38b10a..4d8aa2b85db 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -63,7 +63,6 @@ "network.http-cache.disabled": false, "network.mime.sniff": false, "session-history.max-length": 20, - "shell.builtin-key-shortcuts.enabled": true, "shell.homepage": "https://servo.org", "shell.keep_screen_on.enabled": false, "shell.native-orientation": "both",