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..a8d37e6459c 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. @@ -196,6 +189,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 +215,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 +229,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"), diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index a1fb50d4626..e787f198d48 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -121,19 +121,11 @@ 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; + /// Get the coordinates of the native window, the screen and the framebuffer. + fn get_coordinates(&self) -> EmbedderCoordinates; /// Set the size inside of borders and head fn set_inner_size(&self, ctx: TopLevelBrowsingContextId, size: DeviceUintSize); /// Set the window position @@ -158,9 +150,6 @@ pub trait WindowMethods { /// 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; @@ -193,3 +182,19 @@ pub trait WindowMethods { /// Called when a pipeline panics. fn handle_panic(&self, browser_id: TopLevelBrowsingContextId, reason: String, backtrace: Option); } + +#[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..110660c79f4 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")))] @@ -158,14 +157,16 @@ impl Servo where Window: WindowMethods + 'static { let mut resource_path = resources_dir_path().unwrap(); resource_path.push("shaders"); + let coordinates = window.get_coordinates(); + 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, + // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. + // Tidy up! + None => coordinates.hidpi_factor.get(), } }; @@ -205,7 +206,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. @@ -388,30 +389,6 @@ impl Servo where Window: WindowMethods + 'static { 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), diff --git a/ports/servo/glutin_app/window.rs b/ports/servo/glutin_app/window.rs index f37bcf701a6..cf98c816829 100644 --- a/ports/servo/glutin_app/window.rs +++ b/ports/servo/glutin_app/window.rs @@ -6,7 +6,7 @@ use compositing::compositor_thread::EventLoopWaker; use compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent}; -use compositing::windowing::{WebRenderDebugOption, WindowMethods}; +use compositing::windowing::{EmbedderCoordinates, WebRenderDebugOption, WindowMethods}; use euclid::{Length, TypedPoint2D, TypedVector2D, TypedScale, TypedSize2D}; #[cfg(target_os = "windows")] use gdi32; @@ -881,6 +881,38 @@ impl Window { #[cfg(target_os = "win")] fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers, browser_id: BrowserId) { } + + 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() + } + } + } + + #[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) + } } impl WindowMethods for Window { @@ -888,44 +920,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) - } + 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(); + + 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(); + + let viewport = DeviceUintRect::new(TypedPoint2D::zero(), inner_size); + + 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(ref context) => { - let size = TypedSize2D::new(context.width as f32, context.height as f32); - let origin = TypedPoint2D::zero(); - (size, origin) + 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, + } } - }; - let dpr = self.hidpi_factor(); - ((size * dpr).to_u32(), (point * dpr).to_i32()) - } - - fn screen_size(&self, _: BrowserId) -> DeviceUintSize { - (self.screen_size.to_f32() * self.hidpi_factor()).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) + } } fn set_animation_state(&self, state: AnimationState) { @@ -1011,25 +1043,6 @@ 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, ..) => { @@ -1184,19 +1197,13 @@ impl WindowMethods for Window { (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.page_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.page_height() - 2.0 * LINE_HEIGHT)); self.scroll_window(scroll_location, TouchEventType::Move); }