diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index c9c61283ff8..fc9cd16ebc9 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -26,7 +26,8 @@ use constellation_traits::{ use crossbeam_channel::Sender; use dpi::PhysicalSize; use embedder_traits::{ - Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, ShutdownState, TouchEventType, + Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, ScreenGeometry, ShutdownState, + TouchEventType, }; use euclid::{Box2D, Point2D, Rect, Scale, Size2D, Transform3D}; use fnv::FnvHashMap; @@ -54,11 +55,11 @@ use webrender_api::{ }; use webrender_traits::display_list::{HitTestInfo, ScrollTree}; use webrender_traits::rendering_context::RenderingContext; -use webrender_traits::{CrossProcessCompositorMessage, ImageUpdate}; +use webrender_traits::{CrossProcessCompositorMessage, ImageUpdate, RendererWebView}; use crate::InitialCompositorState; use crate::webview::{UnknownWebView, WebView, WebViewManager}; -use crate::windowing::{self, EmbedderCoordinates, WebRenderDebugOption, WindowMethods}; +use crate::windowing::{self, WebRenderDebugOption, WindowMethods}; #[derive(Debug, PartialEq)] enum UnableToComposite { @@ -167,8 +168,9 @@ pub struct IOCompositor { /// The surfman instance that webrender targets rendering_context: Rc, - /// The coordinates of the native window, its view and the screen. - embedder_coordinates: EmbedderCoordinates, + /// The HighDPI factor of the native window, its view and the screen. + /// TODO: Eventually this should be a property of the `WebView`. + hidpi_factor: Scale, /// The number of frames pending to receive from WebRender. pending_frames: usize, @@ -442,7 +444,7 @@ impl IOCompositor { cursor_pos: DevicePoint::new(0.0, 0.0), })), webviews: WebViewManager::default(), - embedder_coordinates: window.get_coordinates(), + hidpi_factor: window.hidpi_factor(), window, needs_repaint: Cell::default(), page_zoom: Scale::new(1.0), @@ -895,27 +897,46 @@ impl IOCompositor { .collect(); let _ = result_sender.send((font_keys, font_instance_keys)); }, - CrossProcessCompositorMessage::GetClientWindowRect(req) => { - if let Err(e) = req.send(self.embedder_coordinates.window_rect) { - warn!("Sending response to get client window failed ({:?}).", e); + CrossProcessCompositorMessage::GetClientWindowRect(webview_id, response_sender) => { + let screen_geometry = self.webview_screen_geometry(webview_id); + let rect = DeviceIntRect::from_origin_and_size( + screen_geometry.offset, + self.rendering_context.size2d().to_i32(), + ) + .to_f32() / + self.hidpi_factor; + + if let Err(error) = response_sender.send(rect.to_i32()) { + warn!("Sending response to get client window failed ({error:?})."); } }, - CrossProcessCompositorMessage::GetScreenSize(req) => { - if let Err(e) = req.send(self.embedder_coordinates.screen_size) { - warn!("Sending response to get screen size failed ({:?}).", e); + CrossProcessCompositorMessage::GetScreenSize(webview_id, response_sender) => { + let screen_geometry = self.webview_screen_geometry(webview_id); + let screen_size = screen_geometry.size.to_f32() / self.hidpi_factor; + + if let Err(error) = response_sender.send(screen_size.to_i32()) { + warn!("Sending response to get screen size failed ({error:?})."); } }, - CrossProcessCompositorMessage::GetAvailableScreenSize(req) => { - if let Err(e) = req.send(self.embedder_coordinates.available_screen_size) { - warn!( - "Sending response to get screen avail size failed ({:?}).", - e - ); + CrossProcessCompositorMessage::GetAvailableScreenSize(webview_id, response_sender) => { + let screen_geometry = self.webview_screen_geometry(webview_id); + let available_screen_size = + screen_geometry.available_size.to_f32() / self.hidpi_factor; + + if let Err(error) = response_sender.send(available_screen_size.to_i32()) { + warn!("Sending response to get screen size failed ({error:?})."); } }, } } + fn webview_screen_geometry(&self, webview_id: WebViewId) -> ScreenGeometry { + self.webviews + .get(webview_id) + .and_then(|webview| webview.renderer_webview.screen_geometry()) + .unwrap_or_default() + } + /// Handle messages sent to the compositor during the shutdown process. In general, /// the things the compositor can do in this state are limited. It's very important to /// answer any synchronous messages though as other threads might be waiting on the @@ -961,25 +982,27 @@ impl IOCompositor { let _ = result_sender.send((font_keys, font_instance_keys)); }, CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetClientWindowRect( - req, + _, + response_sender, )) => { - if let Err(e) = req.send(self.embedder_coordinates.window_rect) { - warn!("Sending response to get client window failed ({:?}).", e); + if let Err(error) = response_sender.send(Default::default()) { + warn!("Sending response to get client window failed ({error:?})."); } }, - CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetScreenSize(req)) => { - if let Err(e) = req.send(self.embedder_coordinates.screen_size) { - warn!("Sending response to get screen size failed ({:?}).", e); + CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetScreenSize( + _, + response_sender, + )) => { + if let Err(error) = response_sender.send(Default::default()) { + warn!("Sending response to get client window failed ({error:?})."); } }, CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetAvailableScreenSize( - req, + _, + response_sender, )) => { - if let Err(e) = req.send(self.embedder_coordinates.available_screen_size) { - warn!( - "Sending response to get screen avail size failed ({:?}).", - e - ); + if let Err(error) = response_sender.send(Default::default()) { + warn!("Sending response to get client window failed ({error:?})."); } }, CompositorMsg::NewWebRenderFrameReady(..) => { @@ -1102,10 +1125,10 @@ impl IOCompositor { } } - pub fn add_webview(&mut self, webview_id: WebViewId) { + pub fn add_webview(&mut self, webview: Box) { let size = self.rendering_context.size2d().to_f32(); - self.webviews.entry(webview_id).or_insert(WebView::new( - webview_id, + self.webviews.entry(webview.id()).or_insert(WebView::new( + webview, Box2D::from_origin_and_size(Point2D::origin(), size), self.global.clone(), )); @@ -1239,20 +1262,14 @@ impl IOCompositor { } } - pub fn on_embedder_window_moved(&mut self) { - self.embedder_coordinates = self.window.get_coordinates(); - } - pub fn resize_rendering_context(&mut self, new_size: PhysicalSize) -> bool { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return false; } - let old_hidpi_factor = self.embedder_coordinates.hidpi_factor; - self.embedder_coordinates = self.window.get_coordinates(); - if self.embedder_coordinates.hidpi_factor == old_hidpi_factor && - self.rendering_context.size() == new_size - { + let old_hidpi_factor = self.hidpi_factor; + self.hidpi_factor = self.window.hidpi_factor(); + if self.hidpi_factor == old_hidpi_factor && self.rendering_context.size() == new_size { return false; } @@ -1303,10 +1320,6 @@ impl IOCompositor { self.window.set_animation_state(animation_state); } - fn hidpi_factor(&self) -> Scale { - self.embedder_coordinates.hidpi_factor - } - pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale { self.device_pixels_per_page_pixel_not_including_page_zoom() * self.pinch_zoom_level() } @@ -1314,7 +1327,7 @@ impl IOCompositor { fn device_pixels_per_page_pixel_not_including_page_zoom( &self, ) -> Scale { - self.page_zoom * self.hidpi_factor() + self.page_zoom * self.hidpi_factor } pub fn on_zoom_reset_window_event(&mut self) { diff --git a/components/compositing/webview.rs b/components/compositing/webview.rs index 0adeda15f56..58fda6d20e5 100644 --- a/components/compositing/webview.rs +++ b/components/compositing/webview.rs @@ -23,6 +23,7 @@ use webrender_api::units::{DeviceIntPoint, DevicePoint, DeviceRect, LayoutVector use webrender_api::{ ExternalScrollId, HitTestFlags, RenderReasons, SampledScrollOffset, ScrollLocation, }; +use webrender_traits::RendererWebView; use crate::IOCompositor; use crate::compositor::{PipelineDetails, ServoRenderer}; @@ -50,6 +51,10 @@ enum ScrollZoomEvent { pub(crate) struct WebView { /// The [`WebViewId`] of the `WebView` associated with this [`WebViewDetails`]. pub id: WebViewId, + /// The renderer's view of the embedding layer `WebView` as a trait implementation, + /// so that the renderer doesn't need to depend on the embedding layer. This avoids + /// a dependency cycle. + pub renderer_webview: Box, /// The root [`PipelineId`] of the currently displayed page in this WebView. pub root_pipeline_id: Option, pub rect: DeviceRect, @@ -73,9 +78,14 @@ impl Drop for WebView { } impl WebView { - pub(crate) fn new(id: WebViewId, rect: DeviceRect, global: Rc>) -> Self { + pub(crate) fn new( + renderer_webview: Box, + rect: DeviceRect, + global: Rc>, + ) -> Self { Self { - id, + id: renderer_webview.id(), + renderer_webview, root_pipeline_id: None, rect, pipelines: Default::default(), diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 8bd9159fd4c..a73e65f11d1 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -9,7 +9,7 @@ use std::fmt::Debug; use embedder_traits::{EventLoopWaker, MouseButton}; use euclid::Scale; use net::protocols::ProtocolRegistry; -use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize, DeviceIndependentPixel}; +use servo_geometry::DeviceIndependentPixel; use webrender_api::units::{DevicePixel, DevicePoint}; #[derive(Clone)] @@ -37,12 +37,14 @@ pub enum AnimationState { // for creating the GL context, making it current, buffer // swapping, etc. Really that should all be done by surfman. pub trait WindowMethods { - /// Get the coordinates of the native window, the screen and the framebuffer. - fn get_coordinates(&self) -> EmbedderCoordinates; + /// Get the HighDPI factor of the native window, the screen and the framebuffer. + /// TODO(martin): Move this to `RendererWebView` when possible. + fn hidpi_factor(&self) -> Scale; /// 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. + /// TODO(martin): Move this to `RendererWebView` when possible. fn set_animation_state(&self, _state: AnimationState); } @@ -65,15 +67,3 @@ pub trait EmbedderMethods { ProtocolRegistry::default() } } - -#[derive(Clone, Copy, Debug)] -pub struct EmbedderCoordinates { - /// The pixel density of the display. - pub hidpi_factor: Scale, - /// Size of the screen. - pub screen_size: DeviceIndependentIntSize, - /// Size of the available screen space (screen without toolbars and docks). - pub available_screen_size: DeviceIndependentIntSize, - /// Position and size of the native window. - pub window_rect: DeviceIndependentIntRect, -} diff --git a/components/script/dom/screen.rs b/components/script/dom/screen.rs index ff35b2e60f5..0d5a751e273 100644 --- a/components/script/dom/screen.rs +++ b/components/script/dom/screen.rs @@ -35,28 +35,34 @@ impl Screen { } fn screen_size(&self) -> Size2D { - let (send, recv) = + let (sender, receiver) = ipc::channel::(self.global().time_profiler_chan().clone()) .unwrap(); self.window .compositor_api() .sender() - .send(CrossProcessCompositorMessage::GetScreenSize(send)) + .send(CrossProcessCompositorMessage::GetScreenSize( + self.window.webview_id(), + sender, + )) .unwrap(); - let size = recv.recv().unwrap_or(Size2D::zero()).to_u32(); + let size = receiver.recv().unwrap_or(Size2D::zero()).to_u32(); Size2D::new(size.width, size.height) } fn screen_avail_size(&self) -> Size2D { - let (send, recv) = + let (sender, receiver) = ipc::channel::(self.global().time_profiler_chan().clone()) .unwrap(); self.window .compositor_api() .sender() - .send(CrossProcessCompositorMessage::GetAvailableScreenSize(send)) + .send(CrossProcessCompositorMessage::GetAvailableScreenSize( + self.window.webview_id(), + sender, + )) .unwrap(); - let size = recv.recv().unwrap_or(Size2D::zero()).to_u32(); + let size = receiver.recv().unwrap_or(Size2D::zero()).to_u32(); Size2D::new(size.width, size.height) } } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 42c085a81df..2e1faadeaee 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1859,13 +1859,15 @@ impl Window { fn client_window(&self) -> (Size2D, Point2D) { let timer_profile_chan = self.global().time_profiler_chan().clone(); - let (send, recv) = + let (sender, receiver) = ProfiledIpc::channel::(timer_profile_chan).unwrap(); - let _ = self - .compositor_api - .sender() - .send(webrender_traits::CrossProcessCompositorMessage::GetClientWindowRect(send)); - let rect = recv.recv().unwrap_or_default(); + let _ = self.compositor_api.sender().send( + webrender_traits::CrossProcessCompositorMessage::GetClientWindowRect( + self.webview_id(), + sender, + ), + ); + let rect = receiver.recv().unwrap_or_default(); ( Size2D::new(rect.size().width as u32, rect.size().height as u32), Point2D::new(rect.min.x, rect.min.y), diff --git a/components/servo/examples/winit_minimal.rs b/components/servo/examples/winit_minimal.rs index c4995a54224..f19fd9763fe 100644 --- a/components/servo/examples/winit_minimal.rs +++ b/components/servo/examples/winit_minimal.rs @@ -1,6 +1,5 @@ /* 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 https://mozilla.org/MPL/2.0/. */ + * License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::{Cell, RefCell}; use std::error::Error; @@ -13,7 +12,7 @@ use servo_geometry::DeviceIndependentPixel; use tracing::warn; use url::Url; use webrender_api::ScrollLocation; -use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DevicePixel, LayoutVector2D}; +use webrender_api::units::{DeviceIntPoint, DevicePixel, LayoutVector2D}; use winit::application::ApplicationHandler; use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::event::{MouseScrollDelta, WindowEvent}; @@ -250,26 +249,8 @@ impl WindowDelegate { } impl WindowMethods for WindowDelegate { - fn get_coordinates(&self) -> compositing::windowing::EmbedderCoordinates { - let monitor = self - .window - .current_monitor() - .or_else(|| self.window.available_monitors().nth(0)) - .expect("Failed to get winit monitor"); - let scale = - Scale::::new(self.window.scale_factor()); - let window_size = winit_size_to_euclid_size(self.window.outer_size()).to_i32(); - let window_origin = self.window.outer_position().unwrap_or_default(); - let window_origin = winit_position_to_euclid_point(window_origin).to_i32(); - let window_rect = DeviceIntRect::from_origin_and_size(window_origin, window_size); - - compositing::windowing::EmbedderCoordinates { - hidpi_factor: Scale::new(self.window.scale_factor() as f32), - screen_size: (winit_size_to_euclid_size(monitor.size()).to_f64() / scale).to_i32(), - available_screen_size: (winit_size_to_euclid_size(monitor.size()).to_f64() / scale) - .to_i32(), - window_rect: (window_rect.to_f64() / scale).to_i32(), - } + fn hidpi_factor(&self) -> Scale { + Scale::new(self.window.scale_factor() as f32) } fn set_animation_state(&self, state: compositing::windowing::AnimationState) { diff --git a/components/servo/lib.rs b/components/servo/lib.rs index e61a08fff89..ecfcddf85ca 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -321,8 +321,7 @@ impl Servo { None }; - let coordinates: compositing::windowing::EmbedderCoordinates = window.get_coordinates(); - let device_pixel_ratio = coordinates.hidpi_factor.get(); + let device_pixel_ratio = window.hidpi_factor().get(); let viewport_size = rendering_context.size2d(); let (mut webrender, webrender_api_sender) = { diff --git a/components/servo/webview.rs b/components/servo/webview.rs index 78416f565ab..4a0f8fb1f8f 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -13,11 +13,12 @@ use compositing::windowing::WebRenderDebugOption; use constellation_traits::{ConstellationMsg, TraversalDirection}; use dpi::PhysicalSize; use embedder_traits::{ - Cursor, InputEvent, LoadStatus, MediaSessionActionType, Theme, TouchEventType, + Cursor, InputEvent, LoadStatus, MediaSessionActionType, ScreenGeometry, Theme, TouchEventType, }; use url::Url; use webrender_api::ScrollLocation; use webrender_api::units::{DeviceIntPoint, DeviceRect}; +use webrender_traits::RendererWebView; use crate::ConstellationProxy; use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate}; @@ -96,11 +97,10 @@ impl WebView { compositor: Rc>, ) -> Self { let id = WebViewId::new(); - compositor.borrow_mut().add_webview(id); - Self(Rc::new(RefCell::new(WebViewInner { + let webview = Self(Rc::new(RefCell::new(WebViewInner { id, constellation_proxy: constellation_proxy.clone(), - compositor, + compositor: compositor.clone(), delegate: Rc::new(DefaultWebViewDelegate), clipboard_delegate: Rc::new(DefaultClipboardDelegate), rect: DeviceRect::zero(), @@ -111,7 +111,16 @@ impl WebView { favicon_url: None, focused: false, cursor: Cursor::Pointer, - }))) + }))); + + compositor + .borrow_mut() + .add_webview(Box::new(ServoRendererWebView { + weak_handle: webview.weak_handle(), + id, + })); + + webview } fn inner(&self) -> Ref<'_, WebViewInner> { @@ -382,13 +391,6 @@ impl WebView { .resize_rendering_context(new_size); } - pub fn notify_embedder_window_moved(&self) { - self.inner() - .compositor - .borrow_mut() - .on_embedder_window_moved(); - } - pub fn set_zoom(&self, new_zoom: f32) { self.inner() .compositor @@ -452,3 +454,21 @@ impl WebView { self.inner().compositor.borrow_mut().render() } } + +/// A structure used to expose a view of the [`WebView`] to the Servo +/// renderer, without having the Servo renderer depend on the embedding layer. +struct ServoRendererWebView { + id: WebViewId, + weak_handle: Weak>, +} + +impl RendererWebView for ServoRendererWebView { + fn screen_geometry(&self) -> Option { + let webview = WebView::from_weak_handle(&self.weak_handle)?; + webview.delegate().screen_geometry(webview) + } + + fn id(&self) -> WebViewId { + self.id + } +} diff --git a/components/servo/webview_delegate.rs b/components/servo/webview_delegate.rs index 9ea75e32af6..0af15d7e417 100644 --- a/components/servo/webview_delegate.rs +++ b/components/servo/webview_delegate.rs @@ -9,7 +9,7 @@ use constellation_traits::ConstellationMsg; use embedder_traits::{ AllowOrDeny, AuthenticationResponse, ContextMenuResult, Cursor, FilterPattern, GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent, Notification, - PermissionFeature, SimpleDialog, WebResourceRequest, WebResourceResponse, + PermissionFeature, ScreenGeometry, SimpleDialog, WebResourceRequest, WebResourceResponse, WebResourceResponseMsg, }; use ipc_channel::ipc::IpcSender; @@ -297,6 +297,12 @@ impl Drop for InterceptedWebResourceLoad { } pub trait WebViewDelegate { + /// Get the [`ScreenGeometry`] for this [`WebView`]. If this is unimplemented or returns `None` + /// the screen will have the size of the [`WebView`]'s `RenderingContext` and `WebView` will be + /// considered to be positioned at the screen's origin. + fn screen_geometry(&self, _webview: WebView) -> Option { + None + } /// The URL of the currently loaded page in this [`WebView`] has changed. The new /// URL can accessed via [`WebView::url`]. fn notify_url_changed(&self, _webview: WebView, _url: Url) {} diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 006420c3c64..eb3fcde9a6f 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -636,3 +636,22 @@ pub struct NotificationAction { /// Icon's raw image data and metadata. pub icon_resource: Option>, } + +/// Information about a `WebView`'s screen geometry and offset. This is used +/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) +/// CSSOM APIs and `window.screenLeft` / `window.screenTop`. +#[derive(Clone, Copy, Debug, Default)] +pub struct ScreenGeometry { + /// The size of the screen in device pixels. This will be converted to + /// CSS pixels based on the pixel scaling of the `WebView`. + pub size: DeviceIntSize, + /// The available size of the screen in device pixels. This size is the size + /// available for web content on the screen, and should be `size` minus any system + /// toolbars, docks, and interface elements of the browser. This will be converted to + /// CSS pixels based on the pixel scaling of the `WebView`. + pub available_size: DeviceIntSize, + /// The offset of the `WebView` in device pixels for the purposes of the `window.screenLeft` + /// and `window.screenTop` APIs. This will be converted to CSS pixels based on the pixel scaling + /// of the `WebView`. + pub offset: DeviceIntPoint, +} diff --git a/components/shared/webrender/lib.rs b/components/shared/webrender/lib.rs index 9de994f3ca2..c91931f0954 100644 --- a/components/shared/webrender/lib.rs +++ b/components/shared/webrender/lib.rs @@ -14,6 +14,7 @@ use std::sync::{Arc, Mutex}; use base::id::WebViewId; use constellation_traits::CompositorHitTestResult; use display_list::CompositorDisplayListInfo; +use embedder_traits::ScreenGeometry; use euclid::default::Size2D as UntypedSize2D; use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory}; use log::warn; @@ -82,12 +83,12 @@ pub enum CrossProcessCompositorMessage { RemoveFonts(Vec, Vec), /// Get the client window size and position. - GetClientWindowRect(IpcSender), + GetClientWindowRect(WebViewId, IpcSender), /// Get the size of the screen that the client window inhabits. - GetScreenSize(IpcSender), + GetScreenSize(WebViewId, IpcSender), /// Get the available screen size (without toolbars and docks) for the screen /// the client window inhabits. - GetAvailableScreenSize(IpcSender), + GetAvailableScreenSize(WebViewId, IpcSender), } impl fmt::Debug for CrossProcessCompositorMessage { @@ -478,3 +479,11 @@ impl From for ImageData { } } } + +/// A trait that exposes the embedding layer's `WebView` to the Servo renderer. +/// This is to prevent a dependency cycle between the renderer and the embedding +/// layer. +pub trait RendererWebView { + fn id(&self) -> WebViewId; + fn screen_geometry(&self) -> Option; +} diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 613b2807d14..047197a60a8 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -11,13 +11,16 @@ use std::rc::Rc; use std::time::Instant; use std::{env, fs}; +use euclid::Scale; use log::{info, trace, warn}; use servo::compositing::windowing::{AnimationState, WindowMethods}; use servo::config::opts::Opts; use servo::config::prefs::Preferences; use servo::servo_config::pref; +use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_url::ServoUrl; use servo::user_content_manager::{UserContentManager, UserScript}; +use servo::webrender_api::units::DevicePixel; use servo::webxr::glwindow::GlWindowDiscovery; #[cfg(target_os = "windows")] use servo::webxr::openxr::{AppInfo, OpenXrDiscovery}; @@ -140,8 +143,8 @@ impl App { // struct UpcastedWindow(Rc); impl WindowMethods for UpcastedWindow { - fn get_coordinates(&self) -> servo::compositing::windowing::EmbedderCoordinates { - self.0.get_coordinates() + fn hidpi_factor(&self) -> Scale { + self.0.hidpi_factor() } fn set_animation_state(&self, state: AnimationState) { self.0.set_animation_state(state); diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index 71881d41059..b9ebf2e7534 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -392,6 +392,10 @@ impl ServoDelegate for ServoShellServoDelegate { } impl WebViewDelegate for RunningAppState { + fn screen_geometry(&self, _webview: WebView) -> Option { + Some(self.inner().window.screen_geometry()) + } + fn notify_status_text_changed(&self, _webview: servo::WebView, _status: Option) { self.inner_mut().need_update = true; } diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index ae741586be0..f7986001c4d 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -14,18 +14,16 @@ use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vec use keyboard_types::{Modifiers, ShortcutMatcher}; use log::{debug, info}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; -use servo::compositing::windowing::{ - AnimationState, EmbedderCoordinates, WebRenderDebugOption, WindowMethods, -}; +use servo::compositing::windowing::{AnimationState, WebRenderDebugOption, WindowMethods}; use servo::servo_config::pref; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::ScrollLocation; -use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel}; +use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel}; use servo::{ Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, OffscreenRenderingContext, - RenderingContext, Theme, TouchEvent, TouchEventType, TouchId, WebView, WheelDelta, WheelEvent, - WheelMode, WindowRenderingContext, + RenderingContext, ScreenGeometry, Theme, TouchEvent, TouchEventType, TouchId, WebView, + WheelDelta, WheelEvent, WheelMode, WindowRenderingContext, }; use surfman::{Context, Device}; use url::Url; @@ -114,7 +112,7 @@ impl Window { .expect("No monitor detected"); let (screen_size, screen_scale) = servoshell_preferences.screen_size_override.map_or_else( - || (monitor.size(), monitor.scale_factor()), + || (monitor.size(), winit_window.scale_factor()), |size| (PhysicalSize::new(size.width, size.height), 1.0), ); let screen_scale: Scale = @@ -446,6 +444,26 @@ impl Window { } impl WindowPortsMethods for Window { + fn screen_geometry(&self) -> ScreenGeometry { + let hidpi_factor = self.hidpi_factor(); + let toolbar_size = Size2D::new(0.0, (self.toolbar_height.get() * self.hidpi_factor()).0); + + let screen_size = self.screen_size.to_f32() * hidpi_factor; + let available_screen_size = screen_size - toolbar_size; + + // Offset the WebView origin by the toolbar so that it reflects the actual viewport and + // not the window origin. + let window_origin = self.winit_window.inner_position().unwrap_or_default(); + let window_origin = winit_position_to_euclid_point(window_origin).to_f32(); + let offset = window_origin + toolbar_size; + + ScreenGeometry { + size: screen_size.to_i32(), + available_size: available_screen_size.to_i32(), + offset: offset.to_i32(), + } + } + fn device_hidpi_factor(&self) -> Scale { Scale::new(self.winit_window.scale_factor() as f32) } @@ -646,9 +664,6 @@ impl WindowPortsMethods for Window { winit::window::Theme::Dark => Theme::Dark, }); }, - WindowEvent::Moved(_new_position) => { - webview.notify_embedder_window_moved(); - }, WindowEvent::Ime(ime) => match ime { Ime::Enabled => { webview.notify_input_event(InputEvent::Ime(ImeEvent::Composition( @@ -753,23 +768,9 @@ impl WindowPortsMethods for Window { } impl WindowMethods for Window { - fn get_coordinates(&self) -> EmbedderCoordinates { - let window_size = winit_size_to_euclid_size(self.winit_window.outer_size()).to_i32(); - let window_origin = self.winit_window.outer_position().unwrap_or_default(); - let window_origin = winit_position_to_euclid_point(window_origin).to_i32(); - let window_rect = DeviceIntRect::from_origin_and_size(window_origin, window_size); - let window_scale: Scale = - Scale::new(self.winit_window.scale_factor()); - let window_rect = (window_rect.to_f64() / window_scale).to_i32(); - let screen_size = self.screen_size.to_i32(); - - EmbedderCoordinates { - window_rect, - screen_size, - // FIXME: Winit doesn't have API for available size. Fallback to screen size - available_screen_size: screen_size, - hidpi_factor: self.hidpi_factor(), - } + fn hidpi_factor(&self) -> Scale { + self.device_pixel_ratio_override() + .unwrap_or_else(|| self.device_hidpi_factor()) } fn set_animation_state(&self, state: AnimationState) { diff --git a/ports/servoshell/desktop/headless_window.rs b/ports/servoshell/desktop/headless_window.rs index 415bff01f26..76b846b3ebf 100644 --- a/ports/servoshell/desktop/headless_window.rs +++ b/ports/servoshell/desktop/headless_window.rs @@ -8,11 +8,11 @@ use std::cell::Cell; use std::rc::Rc; use euclid::num::Zero; -use euclid::{Box2D, Length, Point2D, Scale, Size2D}; -use servo::compositing::windowing::{AnimationState, EmbedderCoordinates, WindowMethods}; +use euclid::{Length, Scale, Size2D}; +use servo::compositing::windowing::{AnimationState, WindowMethods}; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::units::{DeviceIntSize, DevicePixel}; -use servo::{RenderingContext, SoftwareRenderingContext}; +use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext}; use winit::dpi::PhysicalSize; use super::app_state::RunningAppState; @@ -24,8 +24,7 @@ pub struct Window { fullscreen: Cell, device_pixel_ratio_override: Option>, inner_size: Cell, - screen_size: Size2D, - window_rect: Box2D, + screen_size: Size2D, rendering_context: Rc, } @@ -44,12 +43,11 @@ impl Window { let rendering_context = SoftwareRenderingContext::new(physical_size).expect("Failed to create WR surfman"); - let window_rect = Box2D::from_origin_and_size(Point2D::zero(), size.to_i32()); - - let screen_size = servoshell_preferences.screen_size_override.map_or_else( - || window_rect.size(), - |screen_size_override| screen_size_override.to_i32(), - ); + let screen_size = servoshell_preferences + .screen_size_override + .map_or(inner_size, |screen_size_override| { + (screen_size_override.to_f32() * hidpi_factor).to_i32() + }); let window = Window { animation_state: Cell::new(AnimationState::Idle), @@ -57,7 +55,6 @@ impl Window { device_pixel_ratio_override, inner_size: Cell::new(inner_size), screen_size, - window_rect, rendering_context: Rc::new(rendering_context), }; @@ -70,6 +67,14 @@ impl WindowPortsMethods for Window { winit::window::WindowId::dummy() } + fn screen_geometry(&self) -> servo::ScreenGeometry { + ScreenGeometry { + size: self.screen_size, + available_size: self.screen_size, + offset: Default::default(), + } + } + fn request_resize( &self, webview: &::servo::WebView, @@ -148,13 +153,9 @@ impl WindowPortsMethods for Window { } impl WindowMethods for Window { - fn get_coordinates(&self) -> EmbedderCoordinates { - EmbedderCoordinates { - window_rect: self.window_rect, - screen_size: self.screen_size, - available_screen_size: self.screen_size, - hidpi_factor: self.hidpi_factor(), - } + fn hidpi_factor(&self) -> Scale { + self.device_pixel_ratio_override() + .unwrap_or_else(|| self.device_hidpi_factor()) } fn set_animation_state(&self, state: AnimationState) { diff --git a/ports/servoshell/desktop/window_trait.rs b/ports/servoshell/desktop/window_trait.rs index 678e5142f75..62e31c73045 100644 --- a/ports/servoshell/desktop/window_trait.rs +++ b/ports/servoshell/desktop/window_trait.rs @@ -11,7 +11,7 @@ use euclid::{Length, Scale}; use servo::compositing::windowing::WindowMethods; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel}; -use servo::{Cursor, RenderingContext, WebView}; +use servo::{Cursor, RenderingContext, ScreenGeometry, WebView}; use super::app_state::RunningAppState; @@ -20,10 +20,7 @@ pub const LINE_HEIGHT: f32 = 38.0; pub trait WindowPortsMethods: WindowMethods { fn id(&self) -> winit::window::WindowId; - fn hidpi_factor(&self) -> Scale { - self.device_pixel_ratio_override() - .unwrap_or_else(|| self.device_hidpi_factor()) - } + fn screen_geometry(&self) -> ScreenGeometry; fn device_hidpi_factor(&self) -> Scale; fn device_pixel_ratio_override( &self, diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index bc3ea56a708..ac747c8cf0e 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -11,10 +11,8 @@ use keyboard_types::{CompositionEvent, CompositionState}; use log::{debug, error, info, warn}; use raw_window_handle::{RawWindowHandle, WindowHandle}; use servo::base::id::WebViewId; -use servo::compositing::windowing::{ - AnimationState, EmbedderCoordinates, EmbedderMethods, WindowMethods, -}; -use servo::euclid::{Box2D, Point2D, Rect, Scale, Size2D, Vector2D}; +use servo::compositing::windowing::{AnimationState, EmbedderMethods, WindowMethods}; +use servo::euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::ScrollLocation; use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel}; @@ -683,15 +681,8 @@ impl EmbedderMethods for ServoEmbedderCallbacks { } impl WindowMethods for ServoWindowCallbacks { - fn get_coordinates(&self) -> EmbedderCoordinates { - let coords = self.coordinates.borrow(); - let screen_size = (coords.viewport.size.to_f32() / self.hidpi_factor).to_i32(); - EmbedderCoordinates { - window_rect: Box2D::from_origin_and_size(Point2D::zero(), screen_size), - screen_size, - available_screen_size: screen_size, - hidpi_factor: self.hidpi_factor, - } + fn hidpi_factor(&self) -> Scale { + self.hidpi_factor } fn set_animation_state(&self, state: AnimationState) {