diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 241b7450b96..cdbaf4bbffb 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -21,16 +21,14 @@ use compositing_traits::rendering_context::RenderingContext; use compositing_traits::{ CompositionPipeline, CompositorMsg, ImageUpdate, RendererWebView, SendableFrameTree, }; -use constellation_traits::{ - AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent, WindowSizeType, -}; +use constellation_traits::{AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent}; use crossbeam_channel::Sender; use dpi::PhysicalSize; use embedder_traits::{ AnimationState, CompositorHitTestResult, Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, - ScreenGeometry, ShutdownState, TouchEventType, UntrustedNodeAddress, ViewportDetails, + ShutdownState, TouchEventType, UntrustedNodeAddress, ViewportDetails, }; -use euclid::{Box2D, Point2D, Rect, Scale, Size2D, Transform3D}; +use euclid::{Point2D, Rect, Scale, Size2D, Transform3D}; use fnv::FnvHashMap; use ipc_channel::ipc::{self, IpcReceiver, IpcSharedMemory}; use libc::c_void; @@ -40,7 +38,7 @@ use profile_traits::time::{self as profile_time, ProfilerCategory}; use profile_traits::time_profile; use servo_config::opts; use servo_geometry::DeviceIndependentPixel; -use style_traits::{CSSPixel, PinchZoomFactor}; +use style_traits::CSSPixel; use webrender::{CaptureBits, RenderApi, Transaction}; use webrender_api::units::{ DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutPoint, LayoutRect, @@ -57,7 +55,7 @@ use webrender_api::{ use crate::InitialCompositorState; use crate::webview::{UnknownWebView, WebView}; use crate::webview_manager::WebViewManager; -use crate::windowing::{WebRenderDebugOption, WindowMethods}; +use crate::windowing::WebRenderDebugOption; #[derive(Debug, PartialEq)] enum UnableToComposite { @@ -71,10 +69,6 @@ enum NotReadyToPaint { WaitingOnConstellation, } -// Default viewport constraints -const MAX_ZOOM: f32 = 8.0; -const MIN_ZOOM: f32 = 0.1; - /// Holds the state when running reftests that determines when it is /// safe to save the output image. #[derive(Clone, Copy, Debug, PartialEq)] @@ -134,19 +128,6 @@ pub struct IOCompositor { /// Our top-level browsing contexts. webviews: WebViewManager, - /// The application window. - pub window: Rc, - - /// "Mobile-style" zoom that does not reflow the page. - viewport_zoom: PinchZoomFactor, - - /// Viewport zoom constraints provided by @viewport. - min_viewport_zoom: Option, - max_viewport_zoom: Option, - - /// "Desktop-style" zoom that resizes the viewport to fit the window. - page_zoom: Scale, - /// Tracks whether or not the view needs to be repainted. needs_repaint: Cell, @@ -160,10 +141,6 @@ pub struct IOCompositor { /// The surfman instance that webrender targets rendering_context: Rc, - /// 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, @@ -413,11 +390,7 @@ impl ServoRenderer { } impl IOCompositor { - pub fn new( - window: Rc, - state: InitialCompositorState, - convert_mouse_to_touch: bool, - ) -> Self { + pub fn new(state: InitialCompositorState, convert_mouse_to_touch: bool) -> Self { let compositor = IOCompositor { global: Rc::new(RefCell::new(ServoRenderer { shutdown_state: state.shutdown_state, @@ -435,13 +408,7 @@ impl IOCompositor { cursor_pos: DevicePoint::new(0.0, 0.0), })), webviews: WebViewManager::default(), - hidpi_factor: window.hidpi_factor(), - window, needs_repaint: Cell::default(), - page_zoom: Scale::new(1.0), - viewport_zoom: PinchZoomFactor::new(1.0), - min_viewport_zoom: Some(PinchZoomFactor::new(1.0)), - max_viewport_zoom: None, ready_to_save_state: ReadyState::Unknown, webrender: Some(state.webrender), rendering_context: state.rendering_context, @@ -467,15 +434,8 @@ impl IOCompositor { } } - pub fn default_webview_viewport_details(&self) -> ViewportDetails { - // The division by 1 represents the page's default zoom of 100%, - // and gives us the appropriate CSSPixel type for the viewport. - let hidpi_scale_factor = self.window.hidpi_factor(); - let scaled_viewport_size = self.rendering_context.size2d().to_f32() / hidpi_scale_factor; - ViewportDetails { - size: scaled_viewport_size / Scale::new(1.0), - hidpi_scale_factor: Scale::new(hidpi_scale_factor.0), - } + pub fn rendering_context_size(&self) -> Size2D { + self.rendering_context.size2d() } pub fn webxr_running(&self) -> bool { @@ -577,8 +537,8 @@ impl IOCompositor { webview.on_touch_event_processed(result); }, - CompositorMsg::CreatePng(page_rect, reply) => { - let res = self.render_to_shared_memory(page_rect); + CompositorMsg::CreatePng(webview_id, page_rect, reply) => { + let res = self.render_to_shared_memory(webview_id, page_rect); if let Err(ref e) = res { info!("Error retrieving PNG: {:?}", e); } @@ -646,12 +606,12 @@ impl IOCompositor { }, CompositorMsg::WebDriverMouseButtonEvent(webview_id, action, button, x, y) => { - let dppx = self.device_pixels_per_page_pixel(); - let point = dppx.transform_point(Point2D::new(x, y)); let Some(webview) = self.webviews.get_mut(webview_id) else { warn!("Handling input event for unknown webview: {webview_id}"); return; }; + let dppx = webview.device_pixels_per_page_pixel(); + let point = dppx.transform_point(Point2D::new(x, y)); webview.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { point, action, @@ -660,12 +620,12 @@ impl IOCompositor { }, CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y) => { - let dppx = self.device_pixels_per_page_pixel(); - let point = dppx.transform_point(Point2D::new(x, y)); let Some(webview) = self.webviews.get_mut(webview_id) else { warn!("Handling input event for unknown webview: {webview_id}"); return; }; + let dppx = webview.device_pixels_per_page_pixel(); + let point = dppx.transform_point(Point2D::new(x, y)); webview.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); }, @@ -897,45 +857,38 @@ impl IOCompositor { let _ = result_sender.send((font_keys, font_instance_keys)); }, CompositorMsg::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()) { + let client_window_rect = self + .webviews + .get(webview_id) + .map(|webview| webview.client_window_rect(self.rendering_context.size2d())) + .unwrap_or_default(); + if let Err(error) = response_sender.send(client_window_rect) { warn!("Sending response to get client window failed ({error:?})."); } }, CompositorMsg::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()) { + let screen_size = self + .webviews + .get(webview_id) + .map(WebView::screen_size) + .unwrap_or_default(); + if let Err(error) = response_sender.send(screen_size) { warn!("Sending response to get screen size failed ({error:?})."); } }, CompositorMsg::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()) { + let available_screen_size = self + .webviews + .get(webview_id) + .map(WebView::available_screen_size) + .unwrap_or_default(); + if let Err(error) = response_sender.send(available_screen_size) { 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 @@ -1035,43 +988,50 @@ impl IOCompositor { let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline); builder.begin(); - let zoom_factor = self.device_pixels_per_page_pixel().0; - let zoom_reference_frame = builder.push_reference_frame( + let root_reference_frame = SpatialId::root_reference_frame(root_pipeline); + + let viewport_size = self.rendering_context.size2d().to_f32().to_untyped(); + let viewport_rect = LayoutRect::from_origin_and_size( LayoutPoint::zero(), - SpatialId::root_reference_frame(root_pipeline), - TransformStyle::Flat, - PropertyBinding::Value(Transform3D::scale(zoom_factor, zoom_factor, 1.)), - ReferenceFrameKind::Transform { - is_2d_scale_translation: true, - should_snap: true, - paired_with_perspective: false, - }, - SpatialTreeItemKey::new(0, 0), + LayoutSize::from_untyped(viewport_size), ); - let scaled_viewport_size = - self.rendering_context.size2d().to_f32().to_untyped() / zoom_factor; - let scaled_viewport_rect = LayoutRect::from_origin_and_size( - LayoutPoint::zero(), - LayoutSize::from_untyped(scaled_viewport_size), - ); - - let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect); + let root_clip_id = builder.define_clip_rect(root_reference_frame, viewport_rect); let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]); for (_, webview) in self.webviews.painting_order() { - if let Some(pipeline_id) = webview.root_pipeline_id { - let scaled_webview_rect = webview.rect / zoom_factor; - builder.push_iframe( - LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()), - LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()), - &SpaceAndClipInfo { - spatial_id: zoom_reference_frame, - clip_chain_id, - }, - pipeline_id.into(), - true, - ); - } + let Some(pipeline_id) = webview.root_pipeline_id else { + continue; + }; + + let device_pixels_per_page_pixel = webview.device_pixels_per_page_pixel().0; + let webview_reference_frame = builder.push_reference_frame( + LayoutPoint::zero(), + root_reference_frame, + TransformStyle::Flat, + PropertyBinding::Value(Transform3D::scale( + device_pixels_per_page_pixel, + device_pixels_per_page_pixel, + 1., + )), + ReferenceFrameKind::Transform { + is_2d_scale_translation: true, + should_snap: true, + paired_with_perspective: false, + }, + SpatialTreeItemKey::new(0, 0), + ); + + let scaled_webview_rect = webview.rect / device_pixels_per_page_pixel; + builder.push_iframe( + LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()), + LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()), + &SpaceAndClipInfo { + spatial_id: webview_reference_frame, + clip_chain_id, + }, + pipeline_id.into(), + true, + ); } let built_display_list = builder.end(); @@ -1113,12 +1073,15 @@ impl IOCompositor { } } - pub fn add_webview(&mut self, webview: Box) { - let size = self.rendering_context.size2d().to_f32(); + pub fn add_webview( + &mut self, + webview: Box, + viewport_details: ViewportDetails, + ) { self.webviews.entry(webview.id()).or_insert(WebView::new( - webview, - Box2D::from_origin_and_size(Point2D::origin(), size), self.global.clone(), + webview, + viewport_details, )); } @@ -1147,31 +1110,6 @@ impl IOCompositor { self.send_root_pipeline_display_list(); } - pub fn move_resize_webview(&mut self, webview_id: WebViewId, rect: DeviceRect) { - debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}"); - let rect_changed; - let size_changed; - match self.webviews.get_mut(webview_id) { - Some(webview) => { - rect_changed = rect != webview.rect; - size_changed = rect.size() != webview.rect.size(); - webview.rect = rect; - }, - None => { - warn!("{webview_id}: MoveResizeWebView on unknown webview id"); - return; - }, - }; - - if rect_changed { - if size_changed { - self.send_window_size_message_for_top_level_browser_context(rect, webview_id); - } - - self.send_root_pipeline_display_list(); - } - } - pub fn show_webview( &mut self, webview_id: WebViewId, @@ -1228,37 +1166,46 @@ impl IOCompositor { Ok(()) } - fn send_window_size_message_for_top_level_browser_context( - &self, - rect: DeviceRect, - webview_id: WebViewId, - ) { - // The device pixel ratio used by the style system should include the scale from page pixels - // to device pixels, but not including any pinch zoom. - let hidpi_scale_factor = self.device_pixels_per_page_pixel_not_including_page_zoom(); - let size = rect.size().to_f32() / hidpi_scale_factor; - let msg = EmbedderToConstellationMessage::ChangeViewportDetails( - webview_id, - ViewportDetails { - size, - hidpi_scale_factor, - }, - WindowSizeType::Resize, - ); - if let Err(e) = self.global.borrow().constellation_sender.send(msg) { - warn!("Sending window resize to constellation failed ({:?}).", e); + pub fn move_resize_webview(&mut self, webview_id: WebViewId, rect: DeviceRect) { + if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { + return; } + let Some(webview) = self.webviews.get_mut(webview_id) else { + return; + }; + if !webview.set_rect(rect) { + return; + } + + self.send_root_pipeline_display_list(); + self.set_needs_repaint(RepaintReason::Resize); } - pub fn resize_rendering_context(&mut self, new_size: PhysicalSize) -> bool { + pub fn set_hidpi_scale_factor( + &mut self, + webview_id: WebViewId, + new_scale_factor: Scale, + ) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { - return false; + return; + } + let Some(webview) = self.webviews.get_mut(webview_id) else { + return; + }; + if !webview.set_hidpi_scale_factor(new_scale_factor) { + return; } - 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; + self.send_root_pipeline_display_list(); + self.set_needs_repaint(RepaintReason::Resize); + } + + pub fn resize_rendering_context(&mut self, new_size: PhysicalSize) { + if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { + return; + } + if self.rendering_context.size() == new_size { + return; } self.rendering_context.resize(new_size); @@ -1271,9 +1218,8 @@ impl IOCompositor { transaction.set_document_view(output_region); self.global.borrow_mut().send_transaction(transaction); - self.update_after_zoom_or_hidpi_change(); + self.send_root_pipeline_display_list(); self.set_needs_repaint(RepaintReason::Resize); - true } /// If there are any animations running, dispatches appropriate messages to the constellation. @@ -1294,41 +1240,25 @@ impl IOCompositor { } } - pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale { - self.device_pixels_per_page_pixel_not_including_page_zoom() * self.pinch_zoom_level() - } - - fn device_pixels_per_page_pixel_not_including_page_zoom( - &self, - ) -> Scale { - self.page_zoom * self.hidpi_factor - } - - pub fn on_zoom_reset_window_event(&mut self) { + pub fn on_zoom_reset_window_event(&mut self, webview_id: WebViewId) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return; } - self.page_zoom = Scale::new(1.0); - self.update_after_zoom_or_hidpi_change(); + if let Some(webview) = self.webviews.get_mut(webview_id) { + webview.set_page_zoom(1.0); + } + self.send_root_pipeline_display_list(); } - pub fn on_zoom_window_event(&mut self, magnification: f32) { + pub fn on_zoom_window_event(&mut self, webview_id: WebViewId, magnification: f32) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return; } - self.page_zoom = - Scale::new((self.page_zoom.get() * magnification).clamp(MIN_ZOOM, MAX_ZOOM)); - self.update_after_zoom_or_hidpi_change(); - } - - fn update_after_zoom_or_hidpi_change(&mut self) { - for (webview_id, webview) in self.webviews.painting_order() { - self.send_window_size_message_for_top_level_browser_context(webview.rect, *webview_id); + if let Some(webview) = self.webviews.get_mut(webview_id) { + webview.set_page_zoom(magnification); } - - // Update the root transform in WebRender to reflect the new zoom. self.send_root_pipeline_display_list(); } @@ -1428,13 +1358,19 @@ impl IOCompositor { /// [`IOCompositor`]. If succesful return the output image in shared memory. fn render_to_shared_memory( &mut self, + webview_id: WebViewId, page_rect: Option>, ) -> Result, UnableToComposite> { self.render_inner()?; let size = self.rendering_context.size2d().to_i32(); let rect = if let Some(rect) = page_rect { - let rect = self.device_pixels_per_page_pixel().transform_rect(&rect); + let scale = self + .webviews + .get(webview_id) + .map(WebView::device_pixels_per_page_pixel) + .unwrap_or_else(|| Scale::new(1.0)); + let rect = scale.transform_rect(&rect); let x = rect.origin.x as i32; // We need to convert to the bottom-left origin coordinate @@ -1676,22 +1612,6 @@ impl IOCompositor { self.global.borrow().shutdown_state() != ShutdownState::FinishedShuttingDown } - pub fn pinch_zoom_level(&self) -> Scale { - Scale::new(self.viewport_zoom.get()) - } - - pub(crate) fn set_pinch_zoom_level(&mut self, mut zoom: f32) -> bool { - if let Some(min) = self.min_viewport_zoom { - zoom = f32::max(min.get(), zoom); - } - if let Some(max) = self.max_viewport_zoom { - zoom = f32::min(max.get(), zoom); - } - - let old_zoom = std::mem::replace(&mut self.viewport_zoom, PinchZoomFactor::new(zoom)); - old_zoom != self.viewport_zoom - } - pub fn toggle_webrender_debug(&mut self, option: WebRenderDebugOption) { let Some(webrender) = self.webrender.as_mut() else { return; diff --git a/components/compositing/webview.rs b/components/compositing/webview.rs index 5d365f3b89b..a845080a099 100644 --- a/components/compositing/webview.rs +++ b/components/compositing/webview.rs @@ -9,17 +9,21 @@ use std::rc::Rc; use base::id::{PipelineId, WebViewId}; use compositing_traits::{RendererWebView, SendableFrameTree}; -use constellation_traits::{EmbedderToConstellationMessage, ScrollState}; +use constellation_traits::{EmbedderToConstellationMessage, ScrollState, WindowSizeType}; use embedder_traits::{ AnimationState, CompositorHitTestResult, InputEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, ShutdownState, TouchEvent, TouchEventResult, TouchEventType, - TouchId, + TouchId, ViewportDetails, }; -use euclid::{Point2D, Scale, Vector2D}; +use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D}; use fnv::FnvHashSet; use log::{debug, warn}; +use servo_geometry::DeviceIndependentPixel; +use style_traits::{CSSPixel, PinchZoomFactor}; use webrender::Transaction; -use webrender_api::units::{DeviceIntPoint, DevicePoint, DeviceRect, LayoutVector2D}; +use webrender_api::units::{ + DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutVector2D, +}; use webrender_api::{ ExternalScrollId, HitTestFlags, RenderReasons, SampledScrollOffset, ScrollLocation, }; @@ -28,6 +32,10 @@ use crate::IOCompositor; use crate::compositor::{PipelineDetails, ServoRenderer}; use crate::touch::{TouchHandler, TouchMoveAction, TouchMoveAllowed, TouchSequenceState}; +// Default viewport constraints +const MAX_ZOOM: f32 = 8.0; +const MIN_ZOOM: f32 = 0.1; + #[derive(Clone, Copy)] struct ScrollEvent { /// Scroll by this offset, or to Start or End @@ -65,6 +73,16 @@ pub(crate) struct WebView { pending_scroll_zoom_events: Vec, /// Touch input state machine touch_handler: TouchHandler, + /// "Desktop-style" zoom that resizes the viewport to fit the window. + pub page_zoom: Scale, + /// "Mobile-style" zoom that does not reflow the page. + viewport_zoom: PinchZoomFactor, + /// Viewport zoom constraints provided by @viewport. + min_viewport_zoom: Option, + max_viewport_zoom: Option, + /// The HiDPI scale factor for the `WebView` associated with this renderer. This is controlled + /// by the embedding layer. + hidpi_scale_factor: Scale, } impl Drop for WebView { @@ -78,19 +96,26 @@ impl Drop for WebView { impl WebView { pub(crate) fn new( - renderer_webview: Box, - rect: DeviceRect, global: Rc>, + renderer_webview: Box, + viewport_details: ViewportDetails, ) -> Self { + let hidpi_scale_factor = viewport_details.hidpi_scale_factor; + let size = viewport_details.size * viewport_details.hidpi_scale_factor; Self { id: renderer_webview.id(), renderer_webview, root_pipeline_id: None, - rect, + rect: DeviceRect::from_origin_and_size(DevicePoint::origin(), size), pipelines: Default::default(), touch_handler: TouchHandler::new(), global, pending_scroll_zoom_events: Default::default(), + page_zoom: Scale::new(1.0), + viewport_zoom: PinchZoomFactor::new(1.0), + min_viewport_zoom: Some(PinchZoomFactor::new(1.0)), + max_viewport_zoom: None, + hidpi_scale_factor: Scale::new(hidpi_scale_factor.0), } } @@ -265,7 +290,7 @@ impl WebView { } /// On a Window refresh tick (e.g. vsync) - pub fn on_vsync(&mut self) { + pub(crate) fn on_vsync(&mut self) { if let Some(fling_action) = self.touch_handler.on_vsync() { self.on_scroll_window_event( ScrollLocation::Delta(fling_action.delta), @@ -300,7 +325,7 @@ impl WebView { } } - pub fn notify_input_event(&mut self, event: InputEvent) { + pub(crate) fn notify_input_event(&mut self, event: InputEvent) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return; } @@ -365,7 +390,7 @@ impl WebView { } } - pub fn on_touch_event(&mut self, event: TouchEvent) { + pub(crate) fn on_touch_event(&mut self, event: TouchEvent) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return; } @@ -644,7 +669,7 @@ impl WebView { })); } - pub fn notify_scroll_event( + pub(crate) fn notify_scroll_event( &mut self, scroll_location: ScrollLocation, cursor: DeviceIntPoint, @@ -727,13 +752,12 @@ impl WebView { } } - let zoom_changed = compositor - .set_pinch_zoom_level(compositor.pinch_zoom_level().get() * combined_magnification); + let zoom_changed = + self.set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification); let scroll_result = combined_scroll_event.and_then(|combined_event| { self.scroll_node_at_device_point( combined_event.cursor.to_f32(), combined_event.scroll_location, - compositor, ) }); if !zoom_changed && scroll_result.is_none() { @@ -769,11 +793,10 @@ impl WebView { &mut self, cursor: DevicePoint, scroll_location: ScrollLocation, - compositor: &mut IOCompositor, ) -> Option<(PipelineId, ExternalScrollId, LayoutVector2D)> { let scroll_location = match scroll_location { ScrollLocation::Delta(delta) => { - let device_pixels_per_page = compositor.device_pixels_per_page_pixel(); + let device_pixels_per_page = self.device_pixels_per_page_pixel(); let scaled_delta = (Vector2D::from_untyped(delta.to_untyped()) / device_pixels_per_page) .to_untyped(); @@ -818,8 +841,39 @@ impl WebView { None } + pub(crate) fn pinch_zoom_level(&self) -> Scale { + Scale::new(self.viewport_zoom.get()) + } + + fn set_pinch_zoom_level(&mut self, mut zoom: f32) -> bool { + if let Some(min) = self.min_viewport_zoom { + zoom = f32::max(min.get(), zoom); + } + if let Some(max) = self.max_viewport_zoom { + zoom = f32::min(max.get(), zoom); + } + + let old_zoom = std::mem::replace(&mut self.viewport_zoom, PinchZoomFactor::new(zoom)); + old_zoom != self.viewport_zoom + } + + pub(crate) fn set_page_zoom(&mut self, magnification: f32) { + self.page_zoom = + Scale::new((self.page_zoom.get() * magnification).clamp(MIN_ZOOM, MAX_ZOOM)); + } + + pub(crate) fn device_pixels_per_page_pixel(&self) -> Scale { + self.page_zoom * self.hidpi_scale_factor * self.pinch_zoom_level() + } + + pub(crate) fn device_pixels_per_page_pixel_not_including_pinch_zoom( + &self, + ) -> Scale { + self.page_zoom * self.hidpi_scale_factor + } + /// Simulate a pinch zoom - pub fn set_pinch_zoom(&mut self, magnification: f32) { + pub(crate) fn set_pinch_zoom(&mut self, magnification: f32) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return; } @@ -828,6 +882,71 @@ impl WebView { self.pending_scroll_zoom_events .push(ScrollZoomEvent::PinchZoom(magnification)); } + + fn send_window_size_message(&self) { + // The device pixel ratio used by the style system should include the scale from page pixels + // to device pixels, but not including any pinch zoom. + let device_pixel_ratio = self.device_pixels_per_page_pixel_not_including_pinch_zoom(); + let initial_viewport = self.rect.size().to_f32() / device_pixel_ratio; + let msg = EmbedderToConstellationMessage::ChangeViewportDetails( + self.id, + ViewportDetails { + hidpi_scale_factor: device_pixel_ratio, + size: initial_viewport, + }, + WindowSizeType::Resize, + ); + if let Err(e) = self.global.borrow().constellation_sender.send(msg) { + warn!("Sending window resize to constellation failed ({:?}).", e); + } + } + + /// Set the `hidpi_scale_factor` for this renderer, returning `true` if the value actually changed. + pub(crate) fn set_hidpi_scale_factor( + &mut self, + new_scale: Scale, + ) -> bool { + let old_scale_factor = std::mem::replace(&mut self.hidpi_scale_factor, new_scale); + if self.hidpi_scale_factor == old_scale_factor { + return false; + } + + self.send_window_size_message(); + true + } + + /// Set the `rect` for this renderer, returning `true` if the value actually changed. + pub(crate) fn set_rect(&mut self, new_rect: DeviceRect) -> bool { + let old_rect = std::mem::replace(&mut self.rect, new_rect); + if old_rect.size() != self.rect.size() { + self.send_window_size_message(); + } + old_rect != self.rect + } + + pub(crate) fn client_window_rect( + &self, + rendering_context_size: Size2D, + ) -> Box2D { + let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default(); + let rect = DeviceIntRect::from_origin_and_size( + screen_geometry.offset, + rendering_context_size.to_i32(), + ) + .to_f32() / + self.hidpi_scale_factor; + rect.to_i32() + } + + pub(crate) fn screen_size(&self) -> Size2D { + let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default(); + (screen_geometry.size.to_f32() / self.hidpi_scale_factor).to_i32() + } + + pub(crate) fn available_screen_size(&self) -> Size2D { + let screen_geometry = self.renderer_webview.screen_geometry().unwrap_or_default(); + (screen_geometry.available_size.to_f32() / self.hidpi_scale_factor).to_i32() + } } #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 1ab30e73154..d311f499bcc 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -5,10 +5,8 @@ //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. use embedder_traits::{EventLoopWaker, MouseButton}; -use euclid::Scale; use net::protocols::ProtocolRegistry; -use servo_geometry::DeviceIndependentPixel; -use webrender_api::units::{DevicePixel, DevicePoint}; +use webrender_api::units::DevicePoint; #[derive(Clone)] pub enum MouseWindowEvent { @@ -25,15 +23,6 @@ pub enum WebRenderDebugOption { RenderTargetDebug, } -// TODO: this trait assumes that the window is responsible -// for creating the GL context, making it current, buffer -// swapping, etc. Really that should all be done by surfman. -pub trait WindowMethods { - /// 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; -} - pub trait EmbedderMethods { /// Returns a thread-safe object to wake up the window's event loop. fn create_event_loop_waker(&mut self) -> Box; diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index e1a16e4174f..fe961a299a1 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -4588,9 +4588,12 @@ where self.compositor_proxy .send(CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y)); }, - WebDriverCommandMsg::TakeScreenshot(_, rect, response_sender) => { - self.compositor_proxy - .send(CompositorMsg::CreatePng(rect, response_sender)); + WebDriverCommandMsg::TakeScreenshot(webview_id, rect, response_sender) => { + self.compositor_proxy.send(CompositorMsg::CreatePng( + webview_id, + rect, + response_sender, + )); }, } } diff --git a/components/servo/examples/winit_minimal.rs b/components/servo/examples/winit_minimal.rs index 9f4017b4c3b..edfd532654f 100644 --- a/components/servo/examples/winit_minimal.rs +++ b/components/servo/examples/winit_minimal.rs @@ -5,18 +5,17 @@ use std::cell::RefCell; use std::error::Error; use std::rc::Rc; -use compositing::windowing::{EmbedderMethods, WindowMethods}; -use euclid::{Point2D, Scale, Size2D}; +use compositing::windowing::EmbedderMethods; +use euclid::{Scale, Size2D}; use servo::{ RenderingContext, Servo, TouchEventType, WebView, WebViewBuilder, WindowRenderingContext, }; -use servo_geometry::DeviceIndependentPixel; use tracing::warn; use url::Url; use webrender_api::ScrollLocation; use webrender_api::units::{DeviceIntPoint, DevicePixel, LayoutVector2D}; use winit::application::ApplicationHandler; -use winit::dpi::{PhysicalPosition, PhysicalSize}; +use winit::dpi::PhysicalSize; use winit::event::{MouseScrollDelta, WindowEvent}; use winit::event_loop::EventLoop; use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; @@ -43,7 +42,7 @@ fn main() -> Result<(), Box> { } struct AppState { - window_delegate: Rc, + window: Window, servo: Servo, rendering_context: Rc, webviews: RefCell>, @@ -51,15 +50,17 @@ struct AppState { impl ::servo::WebViewDelegate for AppState { fn notify_new_frame_ready(&self, _: WebView) { - self.window_delegate.window.request_redraw(); + self.window.request_redraw(); } fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option { let webview = WebViewBuilder::new_auxiliary(&self.servo) + .hidpi_scale_factor(Scale::new(self.window.scale_factor() as f32)) .delegate(parent_webview.delegate()) .build(); webview.focus(); webview.raise_to_top(true); + self.webviews.borrow_mut().push(webview.clone()); Some(webview) } @@ -91,7 +92,6 @@ impl ApplicationHandler for App { WindowRenderingContext::new(display_handle, window_handle, window.inner_size()) .expect("Could not create RenderingContext for window."), ); - let window_delegate = Rc::new(WindowDelegate::new(window)); let _ = rendering_context.make_current(); @@ -102,13 +102,12 @@ impl ApplicationHandler for App { Box::new(EmbedderDelegate { waker: waker.clone(), }), - window_delegate.clone(), Default::default(), ); servo.setup_logging(); let app_state = Rc::new(AppState { - window_delegate, + window, servo, rendering_context, webviews: Default::default(), @@ -120,8 +119,10 @@ impl ApplicationHandler for App { let webview = WebViewBuilder::new(&app_state.servo) .url(url) + .hidpi_scale_factor(Scale::new(app_state.window.scale_factor() as f32)) .delegate(app_state.clone()) .build(); + webview.focus(); webview.raise_to_top(true); @@ -239,26 +240,6 @@ impl embedder_traits::EventLoopWaker for Waker { } } -struct WindowDelegate { - window: Window, -} - -impl WindowDelegate { - fn new(window: Window) -> Self { - Self { window } - } -} - -impl WindowMethods for WindowDelegate { - fn hidpi_factor(&self) -> Scale { - Scale::new(self.window.scale_factor() as f32) - } -} - pub fn winit_size_to_euclid_size(size: PhysicalSize) -> Size2D { Size2D::new(size.width, size.height) } - -pub fn winit_position_to_euclid_point(position: PhysicalPosition) -> Point2D { - Point2D::new(position.x, position.y) -} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index f6ac0cd2f9e..642cff60cb0 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -42,7 +42,7 @@ use canvas::WebGLComm; use canvas::canvas_paint_thread::CanvasPaintThread; use canvas_traits::webgl::{GlType, WebGLThreads}; use clipboard_delegate::StringRequest; -use compositing::windowing::{EmbedderMethods, WindowMethods}; +use compositing::windowing::EmbedderMethods; use compositing::{IOCompositor, InitialCompositorState}; pub use compositing_traits::rendering_context::{ OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext, @@ -186,11 +186,8 @@ mod media_platform { /// orchestrating the interaction between JavaScript, CSS layout, /// rendering, and the client window. /// -/// Clients create a `Servo` instance for a given reference-counted type -/// implementing `WindowMethods`, which is the bridge to whatever -/// application Servo is embedded in. Clients then create an event -/// loop to pump messages between the embedding application and -/// various browser components. +// Clients create an event loop to pump messages between the embedding +// application and various browser components. pub struct Servo { delegate: RefCell>, compositor: Rc>, @@ -250,7 +247,7 @@ impl Servo { #[cfg_attr( feature = "tracing", tracing::instrument( - skip(preferences, rendering_context, embedder, window), + skip(preferences, rendering_context, embedder), fields(servo_profiling = true), level = "trace", ) @@ -260,7 +257,6 @@ impl Servo { preferences: Preferences, rendering_context: Rc, mut embedder: Box, - window: Rc, user_content_manager: UserContentManager, ) -> Self { // Global configuration options, parsed from the command line. @@ -484,7 +480,6 @@ impl Servo { // rendered page and display it somewhere. let shutdown_state = Rc::new(Cell::new(ShutdownState::NotShuttingDown)); let compositor = IOCompositor::new( - window, InitialCompositorState { sender: compositor_proxy, receiver: compositor_receiver, @@ -625,10 +620,6 @@ impl Servo { .retain(|_webview_id, webview| webview.strong_count() > 0); } - pub fn pinch_zoom_level(&self) -> f32 { - self.compositor.borrow_mut().pinch_zoom_level().get() - } - pub fn setup_logging(&self) { let constellation_chan = self.constellation_proxy.sender(); let env = env_logger::Env::default(); @@ -724,15 +715,7 @@ impl Servo { let webview_id_and_viewport_details = webview .delegate() .request_open_auxiliary_webview(webview) - .map(|webview| { - let mut viewport = - self.compositor.borrow().default_webview_viewport_details(); - let rect = webview.rect(); - if !rect.is_empty() { - viewport.size = rect.size() / viewport.hidpi_scale_factor; - } - (webview.id(), viewport) - }); + .map(|webview| (webview.id(), webview.viewport_details())); let _ = response_sender.send(webview_id_and_viewport_details); } }, diff --git a/components/servo/tests/common/mod.rs b/components/servo/tests/common/mod.rs index 2807a3134ec..d147ff75722 100644 --- a/components/servo/tests/common/mod.rs +++ b/components/servo/tests/common/mod.rs @@ -7,14 +7,12 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; -use compositing::windowing::{EmbedderMethods, WindowMethods}; +use compositing::windowing::EmbedderMethods; use compositing_traits::rendering_context::{RenderingContext, SoftwareRenderingContext}; use dpi::PhysicalSize; use embedder_traits::EventLoopWaker; use euclid::Scale; use servo::Servo; -use servo_geometry::DeviceIndependentPixel; -use webrender_api::units::DevicePixel; pub struct ServoTest { servo: Servo, @@ -39,13 +37,6 @@ impl ServoTest { } } - struct WindowMethodsImpl; - impl WindowMethods for WindowMethodsImpl { - fn hidpi_factor(&self) -> Scale { - Scale::new(1.0) - } - } - #[derive(Clone)] struct EventLoopWakerImpl(Arc); impl EventLoopWaker for EventLoopWakerImpl { @@ -64,7 +55,6 @@ impl ServoTest { Default::default(), rendering_context.clone(), Box::new(EmbedderMethodsImpl(user_event_triggered)), - Rc::new(WindowMethodsImpl), Default::default(), ); Self { servo } diff --git a/components/servo/webview.rs b/components/servo/webview.rs index 5c687a47f8a..fb4ba6cc136 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -15,10 +15,13 @@ use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection}; use dpi::PhysicalSize; use embedder_traits::{ Cursor, InputEvent, LoadStatus, MediaSessionActionType, ScreenGeometry, Theme, TouchEventType, + ViewportDetails, }; +use euclid::{Point2D, Scale, Size2D}; +use servo_geometry::DeviceIndependentPixel; use url::Url; use webrender_api::ScrollLocation; -use webrender_api::units::{DeviceIntPoint, DeviceRect}; +use webrender_api::units::{DeviceIntPoint, DevicePixel, DeviceRect}; use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate}; use crate::webview_delegate::{DefaultWebViewDelegate, WebViewDelegate}; @@ -75,6 +78,7 @@ pub(crate) struct WebViewInner { pub(crate) clipboard_delegate: Rc, rect: DeviceRect, + hidpi_scale_factor: Scale, load_status: LoadStatus, url: Option, status_text: Option, @@ -96,6 +100,17 @@ impl WebView { pub(crate) fn new(builder: WebViewBuilder) -> Self { let id = WebViewId::new(); let servo = builder.servo; + let size = builder.size.map_or_else( + || { + builder + .servo + .compositor + .borrow() + .rendering_context_size() + .to_f32() + }, + |size| Size2D::new(size.width as f32, size.height as f32), + ); let webview = Self(Rc::new(RefCell::new(WebViewInner { id, @@ -103,7 +118,8 @@ impl WebView { compositor: servo.compositor.clone(), delegate: builder.delegate, clipboard_delegate: Rc::new(DefaultClipboardDelegate), - rect: DeviceRect::zero(), + rect: DeviceRect::from_origin_and_size(Point2D::origin(), size), + hidpi_scale_factor: builder.hidpi_scale_factor, load_status: LoadStatus::Complete, url: None, status_text: None, @@ -114,14 +130,14 @@ impl WebView { cursor: Cursor::Pointer, }))); - builder - .servo - .compositor - .borrow_mut() - .add_webview(Box::new(ServoRendererWebView { + let viewport_details = webview.viewport_details(); + servo.compositor.borrow_mut().add_webview( + Box::new(ServoRendererWebView { weak_handle: webview.weak_handle(), id, - })); + }), + viewport_details, + ); servo .webviews @@ -133,8 +149,8 @@ impl WebView { Url::parse("about:blank").expect("Should always be able to parse 'about:blank'."), ); - let viewport_details = servo.compositor.borrow().default_webview_viewport_details(); - servo + builder + .servo .constellation_proxy .send(EmbedderToConstellationMessage::NewWebView( url.into(), @@ -154,6 +170,17 @@ impl WebView { self.0.borrow_mut() } + pub(crate) fn viewport_details(&self) -> ViewportDetails { + // The division by 1 represents the page's default zoom of 100%, + // and gives us the appropriate CSSPixel type for the viewport. + let inner = self.inner(); + let scaled_viewport_size = inner.rect.size() / inner.hidpi_scale_factor; + ViewportDetails { + size: scaled_viewport_size / Scale::new(1.0), + hidpi_scale_factor: Scale::new(inner.hidpi_scale_factor.0), + } + } + pub(crate) fn from_weak_handle(inner: &Weak>) -> Option { inner.upgrade().map(WebView) } @@ -320,6 +347,25 @@ impl WebView { .move_resize_webview(self.id(), rect); } + pub fn hidpi_scale_factor(&self) -> Scale { + self.inner().hidpi_scale_factor + } + + pub fn set_hidpi_scale_factor( + &self, + new_scale_factor: Scale, + ) { + if self.inner().hidpi_scale_factor == new_scale_factor { + return; + } + + self.inner_mut().hidpi_scale_factor = new_scale_factor; + self.inner() + .compositor + .borrow_mut() + .set_hidpi_scale_factor(self.id(), new_scale_factor); + } + pub fn show(&self, hide_others: bool) { self.inner() .compositor @@ -437,14 +483,14 @@ impl WebView { self.inner() .compositor .borrow_mut() - .on_zoom_window_event(new_zoom); + .on_zoom_window_event(self.id(), new_zoom); } pub fn reset_zoom(&self) { self.inner() .compositor .borrow_mut() - .on_zoom_reset_window_event(); + .on_zoom_reset_window_event(self.id()); } pub fn set_pinch_zoom(&self, new_pinch_zoom: f32) { @@ -535,6 +581,8 @@ pub struct WebViewBuilder<'servo> { delegate: Rc, auxiliary: bool, url: Option, + size: Option>, + hidpi_scale_factor: Scale, } impl<'servo> WebViewBuilder<'servo> { @@ -543,6 +591,8 @@ impl<'servo> WebViewBuilder<'servo> { servo, auxiliary: false, url: None, + size: None, + hidpi_scale_factor: Scale::new(1.0), delegate: Rc::new(DefaultWebViewDelegate), } } @@ -563,6 +613,19 @@ impl<'servo> WebViewBuilder<'servo> { self } + pub fn size(mut self, size: PhysicalSize) -> Self { + self.size = Some(size); + self + } + + pub fn hidpi_scale_factor( + mut self, + hidpi_scale_factor: Scale, + ) -> Self { + self.hidpi_scale_factor = hidpi_scale_factor; + self + } + pub fn build(self) -> WebView { WebView::new(self) } diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index a75223e822d..b598dc1277b 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -70,7 +70,11 @@ pub enum CompositorMsg { /// Script has handled a touch event, and either prevented or allowed default actions. TouchEventProcessed(WebViewId, TouchEventResult), /// Composite to a PNG file and return the Image over a passed channel. - CreatePng(Option>, IpcSender>), + CreatePng( + WebViewId, + Option>, + IpcSender>, + ), /// A reply to the compositor asking if the output image is stable. IsReadyToSaveImageReply(bool), /// Set whether to use less resources by stopping animations. diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 657228e9d44..880178aaff8 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -11,16 +11,12 @@ use std::rc::Rc; use std::time::Instant; use std::{env, fs}; -use euclid::Scale; use log::{info, trace, warn}; -use servo::compositing::windowing::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}; @@ -139,15 +135,6 @@ impl App { // Implements embedder methods, used by libservo and constellation. let embedder = Box::new(EmbedderCallbacks::new(self.waker.clone(), xr_discovery)); - // TODO: Remove this once dyn upcasting coercion stabilises - // - struct UpcastedWindow(Rc); - impl WindowMethods for UpcastedWindow { - fn hidpi_factor(&self) -> Scale { - self.0.hidpi_factor() - } - } - let mut user_content_manager = UserContentManager::new(); for script in load_userscripts(self.servoshell_preferences.userscripts_directory.as_deref()) .expect("Loading userscripts failed") @@ -160,7 +147,6 @@ impl App { self.preferences.clone(), window.rendering_context(), embedder, - Rc::new(UpcastedWindow(window.clone())), user_content_manager, ); servo.setup_logging(); @@ -358,7 +344,7 @@ impl ApplicationHandler for App { // Intercept any ScaleFactorChanged events away from EguiGlow::on_window_event, so // we can use our own logic for calculating the scale factor and set egui’s // scale factor to that value manually. - let desired_scale_factor = window.hidpi_factor().get(); + let desired_scale_factor = window.hidpi_scale_factor().get(); let effective_egui_zoom_factor = desired_scale_factor / scale_factor as f32; info!( @@ -371,6 +357,8 @@ impl ApplicationHandler for App { .egui_ctx .set_zoom_factor(effective_egui_zoom_factor); + state.hidpi_scale_factor_changed(); + // Request a winit redraw event, so we can recomposite, update and paint // the minibrowser, and present the new frame. window.winit_window().unwrap().request_redraw(); diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index d60371d7acb..bb7c16f72e8 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -109,6 +109,7 @@ impl RunningAppState { pub(crate) fn new_toplevel_webview(self: &Rc, url: Url) { let webview = WebViewBuilder::new(self.servo()) .url(url) + .hidpi_scale_factor(self.inner().window.hidpi_scale_factor()) .delegate(self.clone()) .build(); @@ -130,6 +131,14 @@ impl RunningAppState { &self.servo } + pub(crate) fn hidpi_scale_factor_changed(&self) { + let inner = self.inner(); + let new_scale_factor = inner.window.hidpi_scale_factor(); + for webview in inner.webviews.values() { + webview.set_hidpi_scale_factor(new_scale_factor); + } + } + pub(crate) fn save_output_image_if_necessary(&self) { let Some(output_path) = self.servoshell_preferences.output_image_path.as_ref() else { return; @@ -462,6 +471,7 @@ impl WebViewDelegate for RunningAppState { parent_webview: servo::WebView, ) -> Option { let webview = WebViewBuilder::new_auxiliary(&self.servo) + .hidpi_scale_factor(self.inner().window.hidpi_scale_factor()) .delegate(parent_webview.delegate()) .build(); diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index d028d95cb73..2e38d2eed30 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -14,7 +14,7 @@ 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::{WebRenderDebugOption, WindowMethods}; +use servo::compositing::windowing::WebRenderDebugOption; use servo::servo_config::pref; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::ScrollLocation; @@ -252,7 +252,7 @@ impl Window { /// Helper function to handle a click fn handle_mouse(&self, webview: &WebView, button: MouseButton, action: ElementState) { - let max_pixel_dist = 10.0 * self.hidpi_factor().get(); + let max_pixel_dist = 10.0 * self.hidpi_scale_factor().get(); let mouse_button = match &button { MouseButton::Left => ServoMouseButton::Left, MouseButton::Right => ServoMouseButton::Right, @@ -443,8 +443,11 @@ 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 hidpi_factor = self.hidpi_scale_factor(); + let toolbar_size = Size2D::new( + 0.0, + (self.toolbar_height.get() * self.hidpi_scale_factor()).0, + ); let screen_size = self.screen_size.to_f32() * hidpi_factor; let available_screen_size = screen_size - toolbar_size; @@ -462,18 +465,18 @@ impl WindowPortsMethods for Window { } } - fn device_hidpi_factor(&self) -> Scale { + fn device_hidpi_scale_factor(&self) -> Scale { Scale::new(self.winit_window.scale_factor() as f32) } - fn device_pixel_ratio_override( - &self, - ) -> Option> { - self.device_pixel_ratio_override.map(Scale::new) + fn hidpi_scale_factor(&self) -> Scale { + self.device_pixel_ratio_override + .map(Scale::new) + .unwrap_or_else(|| self.device_hidpi_scale_factor()) } fn page_height(&self) -> f32 { - let dpr = self.hidpi_factor(); + let dpr = self.hidpi_scale_factor(); let size = self.winit_window.inner_size(); size.height as f32 * dpr.get() } @@ -483,7 +486,7 @@ impl WindowPortsMethods for Window { } fn request_resize(&self, _: &WebView, size: DeviceIntSize) -> Option { - let toolbar_height = self.toolbar_height() * self.hidpi_factor(); + let toolbar_height = self.toolbar_height() * self.hidpi_scale_factor(); let toolbar_height = toolbar_height.get().ceil() as i32; let total_size = PhysicalSize::new(size.width, size.height + toolbar_height); self.winit_window @@ -587,7 +590,7 @@ impl WindowPortsMethods for Window { }, WindowEvent::CursorMoved { position, .. } => { let mut point = winit_position_to_euclid_point(position).to_f32(); - point.y -= (self.toolbar_height() * self.hidpi_factor()).0; + point.y -= (self.toolbar_height() * self.hidpi_scale_factor()).0; self.webview_relative_mouse_point.set(point); webview.notify_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); @@ -598,7 +601,7 @@ impl WindowPortsMethods for Window { (dx as f64, (dy * LINE_HEIGHT) as f64, WheelMode::DeltaLine) }, MouseScrollDelta::PixelDelta(position) => { - let scale_factor = self.device_hidpi_factor().inverse().get() as f64; + let scale_factor = self.device_hidpi_scale_factor().inverse().get() as f64; let position = position.to_logical(scale_factor); (position.x, position.y, WheelMode::DeltaPixel) }, @@ -728,7 +731,7 @@ impl WindowPortsMethods for Window { // this prevents a crash in the compositor due to invalid surface size self.winit_window.set_min_inner_size(Some(PhysicalSize::new( 1.0, - 1.0 + (self.toolbar_height() * self.hidpi_factor()).0, + 1.0 + (self.toolbar_height() * self.hidpi_scale_factor()).0, ))); } @@ -761,13 +764,6 @@ impl WindowPortsMethods for Window { } } -impl WindowMethods for Window { - fn hidpi_factor(&self) -> Scale { - self.device_pixel_ratio_override() - .unwrap_or_else(|| self.device_hidpi_factor()) - } -} - fn winit_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { match phase { TouchPhase::Started => TouchEventType::Down, diff --git a/ports/servoshell/desktop/headless_window.rs b/ports/servoshell/desktop/headless_window.rs index 4ab202f1a56..bf99b400349 100644 --- a/ports/servoshell/desktop/headless_window.rs +++ b/ports/servoshell/desktop/headless_window.rs @@ -9,7 +9,6 @@ use std::rc::Rc; use euclid::num::Zero; use euclid::{Length, Scale, Size2D}; -use servo::compositing::windowing::WindowMethods; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::units::{DeviceIntSize, DevicePixel}; use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext}; @@ -94,19 +93,18 @@ impl WindowPortsMethods for Window { Some(new_size) } - fn device_hidpi_factor(&self) -> Scale { + fn device_hidpi_scale_factor(&self) -> Scale { Scale::new(1.0) } - fn device_pixel_ratio_override( - &self, - ) -> Option> { + fn hidpi_scale_factor(&self) -> Scale { self.device_pixel_ratio_override + .unwrap_or_else(|| self.device_hidpi_scale_factor()) } fn page_height(&self) -> f32 { let height = self.inner_size.get().height; - let dpr = self.hidpi_factor(); + let dpr = self.hidpi_scale_factor(); height as f32 * dpr.get() } @@ -145,10 +143,3 @@ impl WindowPortsMethods for Window { self.rendering_context.clone() } } - -impl WindowMethods for Window { - fn hidpi_factor(&self) -> Scale { - self.device_pixel_ratio_override() - .unwrap_or_else(|| self.device_hidpi_factor()) - } -} diff --git a/ports/servoshell/desktop/window_trait.rs b/ports/servoshell/desktop/window_trait.rs index 824d50f9c9c..d006578cd1f 100644 --- a/ports/servoshell/desktop/window_trait.rs +++ b/ports/servoshell/desktop/window_trait.rs @@ -8,7 +8,6 @@ use std::rc::Rc; 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, ScreenGeometry, WebView}; @@ -18,13 +17,11 @@ use super::app_state::RunningAppState; // This should vary by zoom level and maybe actual text size (focused or under cursor) pub const LINE_HEIGHT: f32 = 38.0; -pub trait WindowPortsMethods: WindowMethods { +pub trait WindowPortsMethods { fn id(&self) -> winit::window::WindowId; fn screen_geometry(&self) -> ScreenGeometry; - fn device_hidpi_factor(&self) -> Scale; - fn device_pixel_ratio_override( - &self, - ) -> Option>; + fn device_hidpi_scale_factor(&self) -> Scale; + fn hidpi_scale_factor(&self) -> Scale; fn page_height(&self) -> f32; fn get_fullscreen(&self) -> bool; fn handle_winit_event(&self, state: Rc, event: winit::event::WindowEvent); diff --git a/ports/servoshell/egl/android/simpleservo.rs b/ports/servoshell/egl/android/simpleservo.rs index 1f5a6adee61..5bd484a5c84 100644 --- a/ports/servoshell/egl/android/simpleservo.rs +++ b/ports/servoshell/egl/android/simpleservo.rs @@ -83,7 +83,6 @@ pub fn init( let window_callbacks = Rc::new(ServoWindowCallbacks::new( callbacks, RefCell::new(init_opts.coordinates), - init_opts.density, )); let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( @@ -97,13 +96,13 @@ pub fn init( preferences, rendering_context.clone(), embedder_callbacks, - window_callbacks.clone(), Default::default(), ); APP.with(|app| { let app_state = RunningAppState::new( init_opts.url, + init_opts.density, rendering_context, servo, window_callbacks, diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 4bf7cd2b839..8207fb3f2fb 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -11,7 +11,7 @@ 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::{EmbedderMethods, WindowMethods}; +use servo::compositing::windowing::EmbedderMethods; use servo::euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use servo::servo_geometry::DeviceIndependentPixel; use servo::webrender_api::ScrollLocation; @@ -45,19 +45,16 @@ impl Coordinates { pub(super) struct ServoWindowCallbacks { host_callbacks: Box, coordinates: RefCell, - hidpi_factor: Scale, } impl ServoWindowCallbacks { pub(super) fn new( host_callbacks: Box, coordinates: RefCell, - hidpi_factor: f32, ) -> Self { Self { host_callbacks, coordinates, - hidpi_factor: Scale::new(hidpi_factor), } } } @@ -90,6 +87,9 @@ struct RunningAppStateInner { /// Whether or not the animation state has changed. This is used to trigger /// host callbacks indicating that animation state has changed. animating_state_changed: Rc>, + + /// The HiDPI scaling factor to use for the display of [`WebView`]s. + hidpi_scale_factor: Scale, } struct ServoShellServoDelegate { @@ -115,7 +115,7 @@ impl ServoDelegate for ServoShellServoDelegate { } impl WebViewDelegate for RunningAppState { - fn screen_geometry(&self, webview: WebView) -> Option { + fn screen_geometry(&self, _webview: WebView) -> Option { let coord = self.callbacks.coordinates.borrow(); let screen_size = DeviceIntSize::new(coord.viewport.size.width, coord.viewport.size.height); Some(ScreenGeometry { @@ -214,6 +214,7 @@ impl WebViewDelegate for RunningAppState { fn request_open_auxiliary_webview(&self, parent_webview: WebView) -> Option { let webview = WebViewBuilder::new_auxiliary(&self.servo) .delegate(parent_webview.delegate()) + .hidpi_scale_factor(self.inner().hidpi_scale_factor) .build(); self.add(webview.clone()); Some(webview) @@ -275,6 +276,7 @@ impl WebViewDelegate for RunningAppState { impl RunningAppState { pub(super) fn new( initial_url: Option, + hidpi_scale_factor: f32, rendering_context: Rc, servo: Servo, callbacks: Rc, @@ -303,6 +305,7 @@ impl RunningAppState { creation_order: vec![], focused_webview_id: None, animating_state_changed, + hidpi_scale_factor: Scale::new(hidpi_scale_factor), }), }); @@ -313,6 +316,7 @@ impl RunningAppState { pub(crate) fn new_toplevel_webview(self: &Rc, url: Url) { let webview = WebViewBuilder::new(&self.servo) .url(url) + .hidpi_scale_factor(self.inner().hidpi_scale_factor) .delegate(self.clone()) .build(); @@ -715,9 +719,3 @@ impl EmbedderMethods for ServoEmbedderCallbacks { } } } - -impl WindowMethods for ServoWindowCallbacks { - fn hidpi_factor(&self) -> Scale { - self.hidpi_factor - } -} diff --git a/ports/servoshell/egl/ohos/simpleservo.rs b/ports/servoshell/egl/ohos/simpleservo.rs index db9399d8b8d..49c684627c3 100644 --- a/ports/servoshell/egl/ohos/simpleservo.rs +++ b/ports/servoshell/egl/ohos/simpleservo.rs @@ -124,7 +124,6 @@ pub fn init( let window_callbacks = Rc::new(ServoWindowCallbacks::new( callbacks, RefCell::new(coordinates), - options.display_density as f32, )); let embedder_callbacks = Box::new(ServoEmbedderCallbacks::new( @@ -138,12 +137,12 @@ pub fn init( preferences, rendering_context.clone(), embedder_callbacks, - window_callbacks.clone(), Default::default(), ); let app_state = RunningAppState::new( Some(options.url), + options.display_density as f32, rendering_context, servo, window_callbacks,