diff options
author | Martin Robinson <mrobinson@igalia.com> | 2025-04-04 19:06:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-04 17:06:34 +0000 |
commit | fb344ba4e9ace1a2ebe09f0fb7c56be1e8ee4720 (patch) | |
tree | f7b85aa0dd1276bd72c4a211a3443b2ee07f76e2 | |
parent | 7c89e24f344fcef5ab858ff752cdd22624b8d66b (diff) | |
download | servo-fb344ba4e9ace1a2ebe09f0fb7c56be1e8ee4720.tar.gz servo-fb344ba4e9ace1a2ebe09f0fb7c56be1e8ee4720.zip |
constellation: Stop assuming that the viewport is shared by all WebViews (#36312)
The `Constellation` previously held a `window_size` member, but this
assumes that all `WebView`s have the same size. This change removes that
assumption as well as making sure that all `WebView`s pass their size
and HiDIP scaling to the `Constellation` when they are created.
In addition
- `WindowSizeData` is renamed to `ViewportDetails`, as it was
holding more than just the size and it didn't necessarily correspond to
a "window." It's used for tracking viewport data, whether for an
`<iframe>` or the main `WebView` viewport.
- `ViewportDetails` is stored more consistently so that conceptually an
`<iframe>` can also have its own HiDPI scaling. This isn't something
we necessarily want, but it makes everything conceptually simpler.
The goal with this change is to work toward allowing per-`WebView` HiDPI
scaling and sizing. There are still some corresponding changes in the
compositor to make that happen, but they will in a subsequent change.
Testing: This is covered by existing tests. There should be no behavior
changes.
Fixes: This is part of #36232.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
26 files changed, 272 insertions, 256 deletions
diff --git a/Cargo.lock b/Cargo.lock index a099a839bd6..634151d2bc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6433,6 +6433,7 @@ dependencies = [ "base", "canvas_traits", "constellation_traits", + "embedder_traits", "euclid", "fnv", "fonts", diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 90a7bb24cd1..62c9225876a 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -21,13 +21,13 @@ use compositing_traits::{ }; use constellation_traits::{ AnimationTickType, CompositorHitTestResult, ConstellationMsg, PaintMetricEvent, - UntrustedNodeAddress, WindowSizeData, WindowSizeType, + UntrustedNodeAddress, WindowSizeType, }; use crossbeam_channel::Sender; use dpi::PhysicalSize; use embedder_traits::{ Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, ScreenGeometry, ShutdownState, - TouchEventType, + TouchEventType, ViewportDetails, }; use euclid::{Box2D, Point2D, Rect, Scale, Size2D, Transform3D}; use fnv::FnvHashMap; @@ -479,6 +479,17 @@ 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), + } + } + fn set_needs_repaint(&self, reason: RepaintReason) { let mut needs_repaint = self.needs_repaint.get(); needs_repaint.insert(reason); @@ -1248,13 +1259,13 @@ impl IOCompositor { ) { // 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_page_zoom(); - let initial_viewport = rect.size().to_f32() / device_pixel_ratio; - let msg = ConstellationMsg::WindowSize( + 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 = ConstellationMsg::ChangeViewportDetails( webview_id, - WindowSizeData { - device_pixel_ratio, - initial_viewport, + ViewportDetails { + size, + hidpi_scale_factor, }, WindowSizeType::Resize, ); diff --git a/components/constellation/browsingcontext.rs b/components/constellation/browsingcontext.rs index 6f8b24dabcb..0a6974a1f2a 100644 --- a/components/constellation/browsingcontext.rs +++ b/components/constellation/browsingcontext.rs @@ -5,9 +5,8 @@ use std::collections::{HashMap, HashSet}; use base::id::{BrowsingContextGroupId, BrowsingContextId, PipelineId, WebViewId}; -use euclid::Size2D; +use embedder_traits::ViewportDetails; use log::warn; -use style_traits::CSSPixel; use crate::pipeline::Pipeline; @@ -50,8 +49,8 @@ pub struct BrowsingContext { /// The top-level browsing context ancestor pub top_level_id: WebViewId, - /// The size of the frame. - pub size: Size2D<f32, CSSPixel>, + /// The [`ViewportDetails`] of the frame that this [`BrowsingContext`] represents. + pub viewport_details: ViewportDetails, /// Whether this browsing context is in private browsing mode. pub is_private: bool, @@ -85,7 +84,7 @@ impl BrowsingContext { top_level_id: WebViewId, pipeline_id: PipelineId, parent_pipeline_id: Option<PipelineId>, - size: Size2D<f32, CSSPixel>, + viewport_details: ViewportDetails, is_private: bool, inherited_secure_context: Option<bool>, throttled: bool, @@ -96,7 +95,7 @@ impl BrowsingContext { bc_group_id, id, top_level_id, - size, + viewport_details, is_private, inherited_secure_context, throttled, diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 8ef33132966..facfdff3885 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -111,7 +111,7 @@ use canvas_traits::webgl::WebGLThreads; use compositing_traits::{CompositorMsg, CompositorProxy, SendableFrameTree}; use constellation_traits::{ AnimationTickType, CompositorHitTestResult, ConstellationMsg as FromCompositorMsg, LogEntry, - PaintMetricEvent, ScrollState, TraversalDirection, WindowSizeData, WindowSizeType, + PaintMetricEvent, ScrollState, TraversalDirection, WindowSizeType, }; use crossbeam_channel::{Receiver, Sender, select, unbounded}; use devtools_traits::{ @@ -123,7 +123,7 @@ use embedder_traits::user_content_manager::UserContentManager; use embedder_traits::{ Cursor, EmbedderMsg, EmbedderProxy, ImeEvent, InputEvent, MediaSessionActionType, MediaSessionEvent, MediaSessionPlaybackState, MouseButton, MouseButtonAction, MouseButtonEvent, - Theme, WebDriverCommandMsg, WebDriverLoadStatus, + Theme, ViewportDetails, WebDriverCommandMsg, WebDriverLoadStatus, }; use euclid::Size2D; use euclid::default::Size2D as UntypedSize2D; @@ -415,9 +415,6 @@ pub struct Constellation<STF, SWF> { /// and the namespaces are allocated by the constellation. next_pipeline_namespace_id: PipelineNamespaceId, - /// The size of the top-level window. - window_size: WindowSizeData, - /// Bits of state used to interact with the webdriver implementation webdriver: WebDriverData, @@ -601,7 +598,6 @@ where pub fn start( state: InitialConstellationState, layout_factory: Arc<dyn LayoutFactory>, - initial_window_size: WindowSizeData, random_pipeline_closure_probability: Option<f32>, random_pipeline_closure_seed: Option<usize>, hard_fail: bool, @@ -713,7 +709,6 @@ where next_pipeline_namespace_id: PipelineNamespaceId(2), time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, - window_size: initial_window_size, phantom: PhantomData, webdriver: WebDriverData::new(), document_states: HashMap::new(), @@ -877,7 +872,7 @@ where webview_id: WebViewId, parent_pipeline_id: Option<PipelineId>, opener: Option<BrowsingContextId>, - initial_window_size: Size2D<f32, CSSPixel>, + initial_viewport_details: ViewportDetails, // TODO: we have to provide ownership of the LoadData // here, because it will be send on an ipc channel, // and ipc channels take onership of their data. @@ -967,10 +962,7 @@ where resource_threads, time_profiler_chan: self.time_profiler_chan.clone(), mem_profiler_chan: self.mem_profiler_chan.clone(), - window_size: WindowSizeData { - initial_viewport: initial_window_size, - device_pixel_ratio: self.window_size.device_pixel_ratio, - }, + viewport_details: initial_viewport_details, event_loop, load_data, prev_throttled: throttled, @@ -1048,7 +1040,7 @@ where top_level_id: WebViewId, pipeline_id: PipelineId, parent_pipeline_id: Option<PipelineId>, - size: Size2D<f32, CSSPixel>, + viewport_details: ViewportDetails, is_private: bool, inherited_secure_context: Option<bool>, throttled: bool, @@ -1081,7 +1073,7 @@ where top_level_id, pipeline_id, parent_pipeline_id, - size, + viewport_details, is_private, inherited_secure_context, throttled, @@ -1320,8 +1312,8 @@ where }, // Create a new top level browsing context. Will use response_chan to return // the browsing context id. - FromCompositorMsg::NewWebView(url, webview_id) => { - self.handle_new_top_level_browsing_context(url, webview_id, None); + FromCompositorMsg::NewWebView(url, webview_id, viewport_details) => { + self.handle_new_top_level_browsing_context(url, webview_id, viewport_details, None); }, // Close a top level browsing context. FromCompositorMsg::CloseWebView(webview_id) => { @@ -1346,8 +1338,16 @@ where FromCompositorMsg::TraverseHistory(webview_id, direction) => { self.handle_traverse_history_msg(webview_id, direction); }, - FromCompositorMsg::WindowSize(webview_id, new_size, size_type) => { - self.handle_window_size_msg(webview_id, new_size, size_type); + FromCompositorMsg::ChangeViewportDetails( + webview_id, + new_viewport_details, + size_type, + ) => { + self.handle_change_viewport_details_msg( + webview_id, + new_viewport_details, + size_type, + ); }, FromCompositorMsg::ThemeChange(theme) => { self.handle_theme_change(theme); @@ -2714,7 +2714,7 @@ where Some(context) => context, None => return warn!("failed browsing context is missing"), }; - let window_size = browsing_context.size; + let viewport_details = browsing_context.viewport_details; let pipeline_id = browsing_context.pipeline_id; let throttled = browsing_context.throttled; @@ -2759,7 +2759,7 @@ where webview_id, None, opener, - window_size, + viewport_details, new_load_data, sandbox, is_private, @@ -2773,7 +2773,7 @@ where // to avoid closing again in handle_activate_document_msg (though it would be harmless) replace: Some(NeedsToReload::Yes(old_pipeline_id, old_load_data)), new_browsing_context_info: None, - window_size, + viewport_details, }); } @@ -2950,9 +2950,9 @@ where &mut self, url: ServoUrl, webview_id: WebViewId, + viewport_details: ViewportDetails, response_sender: Option<IpcSender<WebDriverLoadStatus>>, ) { - let window_size = self.window_size.initial_viewport; let pipeline_id = PipelineId::new(); let browsing_context_id = BrowsingContextId::from(webview_id); let load_data = LoadData::new( @@ -2993,7 +2993,7 @@ where webview_id, None, None, - window_size, + viewport_details, load_data, sandbox, is_private, @@ -3010,7 +3010,7 @@ where inherited_secure_context: None, throttled, }), - window_size, + viewport_details, }); if let Some(response_sender) = response_sender { @@ -3067,12 +3067,7 @@ where type_, } in iframe_sizes { - let window_size = WindowSizeData { - initial_viewport: size, - device_pixel_ratio: self.window_size.device_pixel_ratio, - }; - - self.resize_browsing_context(window_size, type_, browsing_context_id); + self.resize_browsing_context(size, type_, browsing_context_id); } } @@ -3200,14 +3195,13 @@ where None }; - // https://github.com/rust-lang/rust/issues/59159 - let browsing_context_size = browsing_context.size; + let browsing_context_size = browsing_context.viewport_details; let browsing_context_throttled = browsing_context.throttled; // TODO(servo#30571) revert to debug_assert_eq!() once underlying bug is fixed #[cfg(debug_assertions)] - if !(browsing_context_size == load_info.window_size.initial_viewport) { + if !(browsing_context_size == load_info.viewport_details) { log::warn!( - "debug assertion failed! browsing_context_size == load_info.window_size.initial_viewport" + "debug assertion failed! browsing_context_size == load_info.viewport_details.initial_viewport" ); } @@ -3231,7 +3225,7 @@ where replace, // Browsing context for iframe already exists. new_browsing_context_info: None, - window_size: load_info.window_size.initial_viewport, + viewport_details: load_info.viewport_details, }); } @@ -3295,7 +3289,7 @@ where inherited_secure_context: is_parent_secure, throttled: is_parent_throttled, }), - window_size: load_info.window_size.initial_viewport, + viewport_details: load_info.viewport_details, }); } @@ -3323,8 +3317,8 @@ where opener_webview_id, webview_id_sender, )); - let new_webview_id = match webview_id_receiver.recv() { - Ok(Some(webview_id)) => webview_id, + let (new_webview_id, viewport_details) = match webview_id_receiver.recv() { + Ok(Some((webview_id, viewport_details))) => (webview_id, viewport_details), Ok(None) | Err(_) => { let _ = response_sender.send(None); return; @@ -3409,7 +3403,7 @@ where inherited_secure_context: is_opener_secure, throttled: is_opener_throttled, }), - window_size: self.window_size.initial_viewport, + viewport_details, }); } @@ -3528,10 +3522,10 @@ where return None; }, }; - let (window_size, pipeline_id, parent_pipeline_id, is_private, is_throttled) = + let (viewport_details, pipeline_id, parent_pipeline_id, is_private, is_throttled) = match self.browsing_contexts.get(&browsing_context_id) { Some(ctx) => ( - ctx.size, + ctx.viewport_details, ctx.pipeline_id, ctx.parent_pipeline_id, ctx.is_private, @@ -3608,7 +3602,7 @@ where webview_id, None, opener, - window_size, + viewport_details, load_data, sandbox, is_private, @@ -3621,7 +3615,7 @@ where replace, // `load_url` is always invoked on an existing browsing context. new_browsing_context_info: None, - window_size, + viewport_details, }); Some(new_pipeline_id) }, @@ -3901,7 +3895,7 @@ where top_level_id, old_pipeline_id, parent_pipeline_id, - window_size, + viewport_details, is_private, throttled, ) = match self.browsing_contexts.get(&browsing_context_id) { @@ -3909,7 +3903,7 @@ where ctx.top_level_id, ctx.pipeline_id, ctx.parent_pipeline_id, - ctx.size, + ctx.viewport_details, ctx.is_private, ctx.throttled, ), @@ -3926,7 +3920,7 @@ where top_level_id, parent_pipeline_id, opener, - window_size, + viewport_details, load_data.clone(), sandbox, is_private, @@ -3939,7 +3933,7 @@ where replace: Some(NeedsToReload::Yes(pipeline_id, load_data)), // Browsing context must exist at this point. new_browsing_context_info: None, - window_size, + viewport_details, }); return; }, @@ -4348,14 +4342,15 @@ where }; self.embedder_proxy .send(EmbedderMsg::AllowOpeningWebView(webview_id, chan)); - let webview_id = match port.recv() { - Ok(Some(webview_id)) => webview_id, + let (webview_id, viewport_details) = match port.recv() { + Ok(Some((webview_id, viewport_details))) => (webview_id, viewport_details), Ok(None) => return warn!("Embedder refused to allow opening webview"), Err(error) => return warn!("Failed to receive webview id: {error:?}"), }; self.handle_new_top_level_browsing_context( ServoUrl::parse_with_base(None, "about:blank").expect("Infallible parse"), webview_id, + viewport_details, Some(load_sender), ); let _ = sender.send(webview_id); @@ -4363,8 +4358,14 @@ where WebDriverCommandMsg::FocusWebView(webview_id) => { self.handle_focus_web_view(webview_id); }, - WebDriverCommandMsg::GetWindowSize(_, response_sender) => { - let _ = response_sender.send(self.window_size.initial_viewport); + WebDriverCommandMsg::GetWindowSize(webview_id, response_sender) => { + let browsing_context_id = BrowsingContextId::from(webview_id); + let size = self + .browsing_contexts + .get(&browsing_context_id) + .map(|browsing_context| browsing_context.viewport_details.size) + .unwrap_or_default(); + let _ = response_sender.send(size); }, WebDriverCommandMsg::SetWindowSize(webview_id, size, response_sender) => { self.webdriver.resize_channel = Some(response_sender); @@ -4726,7 +4727,7 @@ where change.webview_id, change.new_pipeline_id, new_context_info.parent_pipeline_id, - change.window_size, + change.viewport_details, new_context_info.is_private, new_context_info.inherited_secure_context, new_context_info.throttled, @@ -4969,25 +4970,23 @@ where feature = "tracing", tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") )] - fn handle_window_size_msg( + fn handle_change_viewport_details_msg( &mut self, webview_id: WebViewId, - new_size: WindowSizeData, + new_viewport_details: ViewportDetails, size_type: WindowSizeType, ) { debug!( - "handle_window_size_msg: {:?}", - new_size.initial_viewport.to_untyped() + "handle_change_viewport_details_msg: {:?}", + new_viewport_details.size.to_untyped() ); let browsing_context_id = BrowsingContextId::from(webview_id); - self.resize_browsing_context(new_size, size_type, browsing_context_id); + self.resize_browsing_context(new_viewport_details, size_type, browsing_context_id); if let Some(response_sender) = self.webdriver.resize_channel.take() { - let _ = response_sender.send(new_size.initial_viewport); + let _ = response_sender.send(new_viewport_details.size); } - - self.window_size = new_size; } /// Called when the window exits from fullscreen mode @@ -5061,7 +5060,7 @@ where // If the rectangle for this pipeline is zero sized, it will // never be painted. In this case, don't query the layout // thread as it won't contribute to the final output image. - if browsing_context.size == Size2D::zero() { + if browsing_context.viewport_details.size == Size2D::zero() { continue; } @@ -5156,12 +5155,12 @@ where )] fn resize_browsing_context( &mut self, - new_size: WindowSizeData, + new_viewport_details: ViewportDetails, size_type: WindowSizeType, browsing_context_id: BrowsingContextId, ) { if let Some(browsing_context) = self.browsing_contexts.get_mut(&browsing_context_id) { - browsing_context.size = new_size.initial_viewport; + browsing_context.viewport_details = new_viewport_details; // Send Resize (or ResizeInactive) messages to each pipeline in the frame tree. let pipeline_id = browsing_context.pipeline_id; let pipeline = match self.pipelines.get(&pipeline_id) { @@ -5170,7 +5169,7 @@ where }; let _ = pipeline.event_loop.send(ScriptThreadMessage::Resize( pipeline.id, - new_size, + new_viewport_details, size_type, )); let pipeline_ids = browsing_context @@ -5181,7 +5180,10 @@ where if let Some(pipeline) = self.pipelines.get(id) { let _ = pipeline .event_loop - .send(ScriptThreadMessage::ResizeInactive(pipeline.id, new_size)); + .send(ScriptThreadMessage::ResizeInactive( + pipeline.id, + new_viewport_details, + )); } } } @@ -5199,7 +5201,7 @@ where if pipeline.browsing_context_id == browsing_context_id { let _ = pipeline.event_loop.send(ScriptThreadMessage::Resize( pipeline.id, - new_size, + new_viewport_details, size_type, )); } diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index fb046d77c33..ffbc3a9b772 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -19,9 +19,9 @@ use base::id::{ use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; use compositing_traits::{CompositionPipeline, CompositorMsg, CompositorProxy}; -use constellation_traits::WindowSizeData; use crossbeam_channel::{Sender, unbounded}; use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg}; +use embedder_traits::ViewportDetails; use embedder_traits::user_content_manager::UserContentManager; use fonts::{SystemFontServiceProxy, SystemFontServiceProxySender}; use ipc_channel::Error; @@ -161,8 +161,8 @@ pub struct InitialPipelineState { /// A channel to the memory profiler thread. pub mem_profiler_chan: profile_mem::ProfilerChan, - /// Information about the initial window size. - pub window_size: WindowSizeData, + /// The initial [`ViewportDetails`] to use when starting this new [`Pipeline`]. + pub viewport_details: ViewportDetails, /// The ID of the pipeline namespace for this script thread. pub pipeline_namespace_id: PipelineNamespaceId, @@ -219,7 +219,7 @@ impl Pipeline { webview_id: state.webview_id, opener: state.opener, load_data: state.load_data.clone(), - window_size: state.window_size, + viewport_details: state.viewport_details, }; if let Err(e) = script_chan.send(ScriptThreadMessage::AttachLayout(new_layout_info)) @@ -275,7 +275,7 @@ impl Pipeline { resource_threads: state.resource_threads, time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, - window_size: state.window_size, + viewport_details: state.viewport_details, script_chan: script_chan.clone(), load_data: state.load_data.clone(), script_port, @@ -484,7 +484,7 @@ pub struct UnprivilegedPipelineContent { resource_threads: ResourceThreads, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, - window_size: WindowSizeData, + viewport_details: ViewportDetails, script_chan: IpcSender<ScriptThreadMessage>, load_data: LoadData, script_port: IpcReceiver<ScriptThreadMessage>, @@ -534,7 +534,7 @@ impl UnprivilegedPipelineContent { time_profiler_sender: self.time_profiler_chan.clone(), memory_profiler_sender: self.mem_profiler_chan.clone(), devtools_server_sender: self.devtools_ipc_sender, - window_size: self.window_size, + viewport_details: self.viewport_details, pipeline_namespace_id: self.pipeline_namespace_id, content_process_shutdown_sender: content_process_shutdown_chan, webgl_chan: self.webgl_chan, diff --git a/components/constellation/session_history.rs b/components/constellation/session_history.rs index 9155ffcfca8..1da2ea4db65 100644 --- a/components/constellation/session_history.rs +++ b/components/constellation/session_history.rs @@ -6,11 +6,10 @@ use std::cmp::PartialEq; use std::fmt; use base::id::{BrowsingContextId, HistoryStateId, PipelineId, WebViewId}; -use euclid::Size2D; +use embedder_traits::ViewportDetails; use log::debug; use script_traits::LoadData; use servo_url::ServoUrl; -use style_traits::CSSPixel; use crate::browsingcontext::NewBrowsingContextInfo; @@ -127,8 +126,8 @@ pub struct SessionHistoryChange { /// easily available when they need to be constructed. pub new_browsing_context_info: Option<NewBrowsingContextInfo>, - /// The size of the viewport for the browsing context. - pub window_size: Size2D<f32, CSSPixel>, + /// The size and hidpi scale factor of the viewport for the browsing context. + pub viewport_details: ViewportDetails, } /// Represents a pipeline or discarded pipeline in a history entry. diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs index fd00d62067b..d7373ef4d93 100644 --- a/components/constellation/tracing.rs +++ b/components/constellation/tracing.rs @@ -58,7 +58,7 @@ mod from_compositor { Self::LoadUrl(..) => target!("LoadUrl"), Self::ClearCache => target!("ClearCache"), Self::TraverseHistory(..) => target!("TraverseHistory"), - Self::WindowSize(..) => target!("WindowSize"), + Self::ChangeViewportDetails(..) => target!("ChangeViewportDetails"), Self::ThemeChange(..) => target!("ThemeChange"), Self::TickAnimation(..) => target!("TickAnimation"), Self::WebDriverCommand(..) => target!("WebDriverCommand"), diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index 47bb932fa9e..58d09700e6e 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -9,7 +9,8 @@ use std::sync::Arc; use app_units::Au; use base::id::{BrowsingContextId, PipelineId}; use data_url::DataUrl; -use euclid::Size2D; +use embedder_traits::ViewportDetails; +use euclid::{Scale, Size2D}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use pixels::Image; use script_layout_interface::IFrameSize; @@ -358,12 +359,17 @@ impl ReplacedContents { }, ReplacedContentKind::IFrame(iframe) => { let size = Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()); + let hidpi_scale_factor = layout_context.shared_context().device_pixel_ratio(); + layout_context.iframe_sizes.lock().insert( iframe.browsing_context_id, IFrameSize { browsing_context_id: iframe.browsing_context_id, pipeline_id: iframe.pipeline_id, - size, + viewport_details: ViewportDetails { + size, + hidpi_scale_factor: Scale::new(hidpi_scale_factor.0), + }, }, ); vec![Fragment::IFrame(ArcRefCell::new(IFrameFragment { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 470ce1d7600..a34a7bf75a5 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -17,7 +17,8 @@ use std::sync::{Arc, LazyLock}; use app_units::Au; use base::Epoch; use base::id::{PipelineId, WebViewId}; -use constellation_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData}; +use constellation_traits::{ScrollState, UntrustedNodeAddress}; +use embedder_traits::ViewportDetails; use embedder_traits::resources::{self, Resource}; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D}; use euclid::{Point2D, Scale, Size2D, Vector2D}; @@ -473,8 +474,8 @@ impl LayoutThread { let device = Device::new( MediaType::screen(), QuirksMode::NoQuirks, - config.window_size.initial_viewport, - Scale::new(config.window_size.device_pixel_ratio.get()), + config.viewport_details.size, + Scale::new(config.viewport_details.hidpi_scale_factor.get()), Box::new(LayoutFontMetricsProvider(config.font_context.clone())), ComputedValues::initial_values_with_font_override(font), // TODO: obtain preferred color scheme from embedder @@ -497,8 +498,8 @@ impl LayoutThread { // Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR epoch: Cell::new(Epoch(1)), viewport_size: Size2D::new( - Au::from_f32_px(config.window_size.initial_viewport.width), - Au::from_f32_px(config.window_size.initial_viewport.height), + Au::from_f32_px(config.viewport_details.size.width), + Au::from_f32_px(config.viewport_details.size.height), ), compositor_api: config.compositor_api, scroll_offsets: Default::default(), @@ -618,11 +619,15 @@ impl LayoutThread { }; let had_used_viewport_units = self.stylist.device().used_viewport_units(); - let viewport_size_changed = self.viewport_did_change(reflow_request.window_size); + let viewport_size_changed = self.viewport_did_change(reflow_request.viewport_details); let theme_changed = self.theme_did_change(reflow_request.theme); if viewport_size_changed || theme_changed { - self.update_device(reflow_request.window_size, reflow_request.theme, &guards); + self.update_device( + reflow_request.viewport_details, + reflow_request.theme, + &guards, + ); } if viewport_size_changed && had_used_viewport_units { @@ -951,11 +956,11 @@ impl LayoutThread { } } - fn viewport_did_change(&mut self, window_size_data: WindowSizeData) -> bool { - let new_pixel_ratio = window_size_data.device_pixel_ratio.get(); + fn viewport_did_change(&mut self, viewport_details: ViewportDetails) -> bool { + let new_pixel_ratio = viewport_details.hidpi_scale_factor.get(); let new_viewport_size = Size2D::new( - Au::from_f32_px(window_size_data.initial_viewport.width), - Au::from_f32_px(window_size_data.initial_viewport.height), + Au::from_f32_px(viewport_details.size.width), + Au::from_f32_px(viewport_details.size.height), ); // TODO: eliminate self.viewport_size in favour of using self.device.au_viewport_size() @@ -975,15 +980,15 @@ impl LayoutThread { /// Update layout given a new viewport. Returns true if the viewport changed or false if it didn't. fn update_device( &mut self, - window_size_data: WindowSizeData, + viewport_details: ViewportDetails, theme: PrefersColorScheme, guards: &StylesheetGuards, ) { let device = Device::new( MediaType::screen(), self.stylist.quirks_mode(), - window_size_data.initial_viewport, - Scale::new(window_size_data.device_pixel_ratio.get()), + viewport_details.size, + Scale::new(viewport_details.hidpi_scale_factor.get()), Box::new(LayoutFontMetricsProvider(self.font_context.clone())), self.stylist.device().default_computed_values().to_arc(), theme, diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index ac9140e65c4..6d59623c966 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -128,7 +128,7 @@ impl DocumentOrShadowRoot { let x = *x as f32; let y = *y as f32; let point = &Point2D::new(x, y); - let viewport = self.window.window_size().initial_viewport; + let viewport = self.window.viewport_details().size; if !has_browsing_context { return None; @@ -176,7 +176,7 @@ impl DocumentOrShadowRoot { let x = *x as f32; let y = *y as f32; let point = &Point2D::new(x, y); - let viewport = self.window.window_size().initial_viewport; + let viewport = self.window.viewport_details().size; if !has_browsing_context { return vec![]; diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index db0b4c63c5f..8193c99c896 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -4344,7 +4344,7 @@ impl Element { if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) || (!in_quirks_mode && *self.root_element() == *self) { - let viewport_dimensions = doc.window().window_size().initial_viewport.round().to_i32(); + let viewport_dimensions = doc.window().viewport_details().size.round().to_i32(); rect.size = Size2D::<i32>::new(viewport_dimensions.width, viewport_dimensions.height); } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index dd4277d18cb..9a680353ad9 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -6,8 +6,8 @@ use std::cell::Cell; use base::id::{BrowsingContextId, PipelineId, WebViewId}; use bitflags::bitflags; -use constellation_traits::WindowSizeData; use dom_struct::dom_struct; +use embedder_traits::ViewportDetails; use html5ever::{LocalName, Prefix, local_name, namespace_url, ns}; use js::rust::HandleObject; use net_traits::ReferrerPolicy; @@ -196,12 +196,12 @@ impl HTMLIFrameElement { history_handling, }; - let window_size = WindowSizeData { - initial_viewport: window - .get_iframe_size_if_known(browsing_context_id, can_gc) - .unwrap_or_default(), - device_pixel_ratio: window.device_pixel_ratio(), - }; + let viewport_details = window + .get_iframe_viewport_details_if_known(browsing_context_id, can_gc) + .unwrap_or_else(|| ViewportDetails { + hidpi_scale_factor: window.device_pixel_ratio(), + ..Default::default() + }); match pipeline_type { PipelineType::InitialAboutBlank => { @@ -212,7 +212,7 @@ impl HTMLIFrameElement { load_data: load_data.clone(), old_pipeline_id, sandbox: sandboxed, - window_size, + viewport_details, }; window .as_global_scope() @@ -227,7 +227,7 @@ impl HTMLIFrameElement { webview_id, opener: None, load_data, - window_size, + viewport_details, }; self.pipeline_id.set(Some(new_pipeline_id)); @@ -239,7 +239,7 @@ impl HTMLIFrameElement { load_data, old_pipeline_id, sandbox: sandboxed, - window_size, + viewport_details, }; window .as_global_scope() diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index bec3b2018f7..ee23270a549 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -808,8 +808,8 @@ impl HTMLImageElement { let device_pixel_ratio = self .owner_document() .window() - .window_size() - .device_pixel_ratio + .viewport_details() + .hidpi_scale_factor .get() as f64; for (index, image_source) in img_sources.iter().enumerate() { let current_den = image_source.descriptor.density.unwrap(); diff --git a/components/script/dom/intersectionobserver.rs b/components/script/dom/intersectionobserver.rs index 81ac8a1337d..ec98116d3a4 100644 --- a/components/script/dom/intersectionobserver.rs +++ b/components/script/dom/intersectionobserver.rs @@ -444,7 +444,7 @@ impl IntersectionObserver { // > (note that this processing step can only be reached if the document is fully active). // TODO: viewport should consider native scrollbar if exist. Recheck Servo's scrollbar approach. document.map(|document| { - let viewport = document.window().window_size().initial_viewport; + let viewport = document.window().viewport_details().size; Rect::from_size(Size2D::new( Au::from_f32_px(viewport.width), Au::from_f32_px(viewport.height), diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 84f8deb16b1..57c90354dba 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -21,7 +21,7 @@ use base64::Engine; #[cfg(feature = "bluetooth")] use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLChan; -use constellation_traits::{ScrollState, WindowSizeData, WindowSizeType}; +use constellation_traits::{ScrollState, WindowSizeType}; use crossbeam_channel::{Sender, unbounded}; use cssparser::{Parser, ParserInput, SourceLocation}; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; @@ -29,7 +29,7 @@ use dom_struct::dom_struct; use embedder_traits::user_content_manager::{UserContentManager, UserScript}; use embedder_traits::{ AlertResponse, ConfirmResponse, EmbedderMsg, PromptResponse, SimpleDialog, Theme, - WebDriverJSError, WebDriverJSResult, + ViewportDetails, WebDriverJSError, WebDriverJSResult, }; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect}; use euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; @@ -257,7 +257,7 @@ pub(crate) struct Window { /// Most recent unhandled resize event, if any. #[no_trace] - unhandled_resize_event: DomRefCell<Option<(WindowSizeData, WindowSizeType)>>, + unhandled_resize_event: DomRefCell<Option<(ViewportDetails, WindowSizeType)>>, /// Platform theme. #[no_trace] @@ -274,9 +274,9 @@ pub(crate) struct Window { #[ignore_malloc_size_of = "Rc<T> is hard"] js_runtime: DomRefCell<Option<Rc<Runtime>>>, - /// The current size of the window, in pixels. + /// The [`ViewportDetails`] of this [`Window`]'s frame. #[no_trace] - window_size: Cell<WindowSizeData>, + viewport_details: Cell<ViewportDetails>, /// A handle for communicating messages to the bluetooth thread. #[no_trace] @@ -1300,9 +1300,9 @@ impl WindowMethods<crate::DomTypeHolder> for Window { // https://drafts.csswg.org/cssom-view/#dom-window-innerheight //TODO Include Scrollbar fn InnerHeight(&self) -> i32 { - self.window_size + self.viewport_details .get() - .initial_viewport + .size .height .to_i32() .unwrap_or(0) @@ -1311,12 +1311,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window { // https://drafts.csswg.org/cssom-view/#dom-window-innerwidth //TODO Include Scrollbar fn InnerWidth(&self) -> i32 { - self.window_size - .get() - .initial_viewport - .width - .to_i32() - .unwrap_or(0) + self.viewport_details.get().size.width.to_i32().unwrap_or(0) } // https://drafts.csswg.org/cssom-view/#dom-window-scrollx @@ -1822,7 +1817,7 @@ impl Window { // Step 5 & 6 // TODO: Remove scrollbar dimensions. - let viewport = self.window_size.get().initial_viewport; + let viewport = self.viewport_details.get().size; // Step 7 & 8 // TODO: Consider `block-end` and `inline-end` overflow direction. @@ -1885,7 +1880,7 @@ impl Window { } pub(crate) fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> { - self.window_size.get().device_pixel_ratio + self.viewport_details.get().hidpi_scale_factor } fn client_window(&self) -> (Size2D<u32, CSSPixel>, Point2D<i32, CSSPixel>) { @@ -1994,7 +1989,7 @@ impl Window { document: document.upcast::<Node>().to_trusted_node_address(), dirty_root, stylesheets_changed, - window_size: self.window_size.get(), + viewport_details: self.viewport_details.get(), origin: self.origin().immutable().clone(), reflow_goal, dom_count: document.dom_count(), @@ -2050,7 +2045,7 @@ impl Window { let size_messages = self .Document() .iframes_mut() - .handle_new_iframe_sizes_after_layout(results.iframe_sizes, self.device_pixel_ratio()); + .handle_new_iframe_sizes_after_layout(results.iframe_sizes); if !size_messages.is_empty() { self.send_to_constellation(ScriptMsg::IFrameSizes(size_messages)); } @@ -2364,11 +2359,11 @@ impl Window { /// If the given |browsing_context_id| refers to an `<iframe>` that is an element /// in this [`Window`] and that `<iframe>` has been laid out, return its size. /// Otherwise, return `None`. - pub(crate) fn get_iframe_size_if_known( + pub(crate) fn get_iframe_viewport_details_if_known( &self, browsing_context_id: BrowsingContextId, can_gc: CanGc, - ) -> Option<Size2D<f32, CSSPixel>> { + ) -> Option<ViewportDetails> { // Reflow might fail, but do a best effort to return the right size. self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery, can_gc); self.Document() @@ -2533,12 +2528,12 @@ impl Window { }; } - pub(crate) fn set_window_size(&self, size: WindowSizeData) { - self.window_size.set(size); + pub(crate) fn set_viewport_details(&self, size: ViewportDetails) { + self.viewport_details.set(size); } - pub(crate) fn window_size(&self) -> WindowSizeData { - self.window_size.get() + pub(crate) fn viewport_details(&self) -> ViewportDetails { + self.viewport_details.get() } /// Handle a theme change request, triggering a reflow is any actual change occured. @@ -2563,13 +2558,13 @@ impl Window { self.dom_static.windowproxy_handler } - pub(crate) fn add_resize_event(&self, event: WindowSizeData, event_type: WindowSizeType) { + pub(crate) fn add_resize_event(&self, event: ViewportDetails, event_type: WindowSizeType) { // Whenever we receive a new resize event we forget about all the ones that came before // it, to avoid unnecessary relayouts *self.unhandled_resize_event.borrow_mut() = Some((event, event_type)) } - pub(crate) fn take_unhandled_resize_event(&self) -> Option<(WindowSizeData, WindowSizeType)> { + pub(crate) fn take_unhandled_resize_event(&self) -> Option<(ViewportDetails, WindowSizeType)> { self.unhandled_resize_event.borrow_mut().take() } @@ -2685,7 +2680,7 @@ impl Window { return false; }; - if self.window_size() == new_size { + if self.viewport_details() == new_size { return false; } @@ -2693,9 +2688,9 @@ impl Window { debug!( "Resizing Window for pipeline {:?} from {:?} to {new_size:?}", self.pipeline_id(), - self.window_size(), + self.viewport_details(), ); - self.set_window_size(new_size); + self.set_viewport_details(new_size); // http://dev.w3.org/csswg/cssom-view/#resizing-viewports if size_type == WindowSizeType::Resize { @@ -2823,7 +2818,7 @@ impl Window { control_chan: IpcSender<ScriptThreadMessage>, pipeline_id: PipelineId, parent_info: Option<PipelineId>, - window_size: WindowSizeData, + viewport_details: ViewportDetails, origin: MutableOrigin, creator_url: ServoUrl, navigation_start: CrossProcessInstant, @@ -2848,7 +2843,7 @@ impl Window { let initial_viewport = f32_rect_to_au_rect(UntypedRect::new( Point2D::zero(), - window_size.initial_viewport.to_untyped(), + viewport_details.size.to_untyped(), )); let win = Box::new(Self { @@ -2894,7 +2889,7 @@ impl Window { bluetooth_extra_permission_data: BluetoothExtraPermissionData::new(), page_clip_rect: Cell::new(MaxRect::max_rect()), unhandled_resize_event: Default::default(), - window_size: Cell::new(window_size), + viewport_details: Cell::new(viewport_details), current_viewport: Cell::new(initial_viewport.to_untyped()), layout_blocker: Cell::new(LayoutBlocker::WaitingForParse), current_state: Cell::new(WindowState::Alive), diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 1278a0af115..4bbdf271252 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -326,7 +326,7 @@ impl WindowProxy { webview_id: response.new_webview_id, opener: Some(self.browsing_context_id), load_data, - window_size: window.window_size(), + viewport_details: window.viewport_details(), }; ScriptThread::process_attach_layout(new_layout_info, document.origin().clone()); // TODO: if noopener is false, copy the sessionStorage storage area of the creator origin. diff --git a/components/script/iframe_collection.rs b/components/script/iframe_collection.rs index caf40009fe3..01405881fa6 100644 --- a/components/script/iframe_collection.rs +++ b/components/script/iframe_collection.rs @@ -6,13 +6,11 @@ use std::cell::Cell; use std::default::Default; use base::id::BrowsingContextId; -use constellation_traits::{WindowSizeData, WindowSizeType}; -use euclid::{Scale, Size2D}; +use constellation_traits::WindowSizeType; +use embedder_traits::ViewportDetails; use fnv::FnvHashMap; use script_layout_interface::IFrameSizes; use script_traits::IFrameSizeMsg; -use style_traits::CSSPixel; -use webrender_api::units::DevicePixel; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::{Dom, DomRoot}; @@ -26,7 +24,7 @@ use crate::script_thread::with_script_thread; pub(crate) struct IFrame { pub(crate) element: Dom<HTMLIFrameElement>, #[no_trace] - pub(crate) size: Option<Size2D<f32, CSSPixel>>, + pub(crate) size: Option<ViewportDetails>, } #[derive(Default, JSTraceable, MallocSizeOf)] @@ -98,11 +96,11 @@ impl IFrameCollection { /// Set the size of an `<iframe>` in the collection given its `BrowsingContextId` and /// the new size. Returns the old size. - pub(crate) fn set_size( + pub(crate) fn set_viewport_details( &mut self, browsing_context_id: BrowsingContextId, - new_size: Size2D<f32, CSSPixel>, - ) -> Option<Size2D<f32, CSSPixel>> { + new_size: ViewportDetails, + ) -> Option<ViewportDetails> { self.get_mut(browsing_context_id) .expect("Tried to set a size for an unknown <iframe>") .size @@ -115,7 +113,6 @@ impl IFrameCollection { pub(crate) fn handle_new_iframe_sizes_after_layout( &mut self, new_iframe_sizes: IFrameSizes, - device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>, ) -> Vec<IFrameSizeMsg> { if new_iframe_sizes.is_empty() { return vec![]; @@ -123,37 +120,35 @@ impl IFrameCollection { new_iframe_sizes .into_iter() - .filter_map(|(browsing_context_id, size)| { + .filter_map(|(browsing_context_id, iframe_size)| { // Batch resize message to any local `Pipeline`s now, rather than waiting for them // to filter asynchronously through the `Constellation`. This allows the new value // to be reflected immediately in layout. - let new_size = size.size; + let viewport_details = iframe_size.viewport_details; with_script_thread(|script_thread| { script_thread.handle_resize_message( - size.pipeline_id, - WindowSizeData { - initial_viewport: new_size, - device_pixel_ratio, - }, + iframe_size.pipeline_id, + viewport_details, WindowSizeType::Resize, ); }); - let old_size = self.set_size(browsing_context_id, new_size); + let old_viewport_details = + self.set_viewport_details(browsing_context_id, viewport_details); // The `Constellation` should be up-to-date even when the in-ScriptThread pipelines // might not be. - if old_size == Some(size.size) { + if old_viewport_details == Some(viewport_details) { return None; } - let size_type = match old_size { + let size_type = match old_viewport_details { Some(_) => WindowSizeType::Resize, None => WindowSizeType::Initial, }; Some(IFrameSizeMsg { browsing_context_id, - size: new_size, + size: viewport_details, type_: size_type, }) }) diff --git a/components/script/navigation.rs b/components/script/navigation.rs index 761492b79bf..2c22e25c123 100644 --- a/components/script/navigation.rs +++ b/components/script/navigation.rs @@ -10,9 +10,9 @@ use std::cell::Cell; use base::cross_process_instant::CrossProcessInstant; use base::id::{BrowsingContextId, PipelineId, WebViewId}; -use constellation_traits::WindowSizeData; use content_security_policy::Destination; use crossbeam_channel::Sender; +use embedder_traits::ViewportDetails; use http::header; use net_traits::request::{ CredentialsMode, InsecureRequestsPolicy, RedirectMode, RequestBuilder, RequestMode, @@ -138,7 +138,7 @@ pub(crate) struct InProgressLoad { pub(crate) opener: Option<BrowsingContextId>, /// The current window size associated with this pipeline. #[no_trace] - pub(crate) window_size: WindowSizeData, + pub(crate) viewport_details: ViewportDetails, /// The activity level of the document (inactive, active or fully active). #[no_trace] pub(crate) activity: DocumentActivity, @@ -170,7 +170,7 @@ impl InProgressLoad { webview_id: WebViewId, parent_info: Option<PipelineId>, opener: Option<BrowsingContextId>, - window_size: WindowSizeData, + viewport_details: ViewportDetails, origin: MutableOrigin, load_data: LoadData, ) -> InProgressLoad { @@ -181,7 +181,7 @@ impl InProgressLoad { webview_id, parent_info, opener, - window_size, + viewport_details, activity: DocumentActivity::FullyActive, throttled: false, origin, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 42241ae83ab..b3a8762e7ac 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -36,7 +36,7 @@ use base::cross_process_instant::CrossProcessInstant; use base::id::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespace, WebViewId}; use canvas_traits::webgl::WebGLPipeline; use chrono::{DateTime, Local}; -use constellation_traits::{CompositorHitTestResult, ScrollState, WindowSizeData, WindowSizeType}; +use constellation_traits::{CompositorHitTestResult, ScrollState, WindowSizeType}; use crossbeam_channel::unbounded; use devtools_traits::{ CSSError, DevtoolScriptControlMsg, DevtoolsPageInfo, NavigationState, @@ -44,7 +44,7 @@ use devtools_traits::{ }; use embedder_traits::user_content_manager::UserContentManager; use embedder_traits::{ - EmbedderMsg, InputEvent, MediaSessionActionType, Theme, WebDriverScriptCommand, + EmbedderMsg, InputEvent, MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand, }; use euclid::default::Rect; use fonts::{FontContext, SystemFontServiceProxy}; @@ -401,7 +401,7 @@ impl ScriptThreadFactory for ScriptThread { let parent_info = state.parent_info; let opener = state.opener; let memory_profiler_sender = state.memory_profiler_sender.clone(); - let window_size = state.window_size; + let viewport_details = state.viewport_details; let script_thread = ScriptThread::new(state, layout_factory, system_font_service); @@ -418,7 +418,7 @@ impl ScriptThreadFactory for ScriptThread { webview_id, parent_info, opener, - window_size, + viewport_details, origin, load_data, )); @@ -2337,18 +2337,18 @@ impl ScriptThread { pub(crate) fn handle_resize_message( &self, id: PipelineId, - size: WindowSizeData, + viewport_details: ViewportDetails, size_type: WindowSizeType, ) { self.profile_event(ScriptThreadEventCategory::Resize, Some(id), || { let window = self.documents.borrow().find_window(id); if let Some(ref window) = window { - window.add_resize_event(size, size_type); + window.add_resize_event(viewport_details, size_type); return; } let mut loads = self.incomplete_loads.borrow_mut(); if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) { - load.window_size = size; + load.viewport_details = viewport_details; } }) } @@ -2390,7 +2390,7 @@ impl ScriptThread { webview_id, opener, load_data, - window_size, + viewport_details, } = new_layout_info; // Kick off the fetch for the new resource. @@ -2401,7 +2401,7 @@ impl ScriptThread { webview_id, parent_info, opener, - window_size, + viewport_details, origin, load_data, ); @@ -2647,10 +2647,10 @@ impl ScriptThread { } /// Window was resized, but this script was not active, so don't reflow yet - fn handle_resize_inactive_msg(&self, id: PipelineId, new_size: WindowSizeData) { + fn handle_resize_inactive_msg(&self, id: PipelineId, new_viewport_details: ViewportDetails) { let window = self.documents.borrow().find_window(id) .expect("ScriptThread: received a resize msg for a pipeline not in this script thread. This is a bug."); - window.set_window_size(new_size); + window.set_viewport_details(new_viewport_details); } /// We have received notification that the response associated with a load has completed. @@ -3066,7 +3066,7 @@ impl ScriptThread { font_context: font_context.clone(), time_profiler_chan: self.senders.time_profiler_sender.clone(), compositor_api: self.compositor_api.clone(), - window_size: incomplete.window_size, + viewport_details: incomplete.viewport_details, }; // Create the window and document objects. @@ -3088,7 +3088,7 @@ impl ScriptThread { self.senders.constellation_sender.clone(), incomplete.pipeline_id, incomplete.parent_info, - incomplete.window_size, + incomplete.viewport_details, origin.clone(), final_url.clone(), incomplete.navigation_start, diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 624110cc0ad..3bd0e1443a8 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -58,12 +58,11 @@ use constellation::{ Constellation, FromCompositorLogger, FromScriptLogger, InitialConstellationState, UnprivilegedContent, }; -use constellation_traits::{ConstellationMsg, WindowSizeData}; +use constellation_traits::ConstellationMsg; use crossbeam_channel::{Receiver, Sender, unbounded}; use embedder_traits::user_content_manager::UserContentManager; pub use embedder_traits::*; use env_logger::Builder as EnvLoggerBuilder; -use euclid::Scale; use fonts::SystemFontService; #[cfg(all( not(target_os = "windows"), @@ -321,9 +320,6 @@ impl Servo { None }; - let device_pixel_ratio = window.hidpi_factor().get(); - let viewport_size = rendering_context.size2d(); - let (mut webrender, webrender_api_sender) = { let mut debug_flags = webrender::DebugFlags::empty(); debug_flags.set( @@ -389,7 +385,7 @@ impl Servo { }; let webrender_api = webrender_api_sender.create_api(); - let webrender_document = webrender_api.add_document(viewport_size.to_i32()); + let webrender_document = webrender_api.add_document(rendering_context.size2d().to_i32()); // Important that this call is done in a single-threaded fashion, we // can't defer it after `create_constellation` has started. @@ -451,14 +447,6 @@ impl Servo { webrender.set_external_image_handler(external_image_handlers); - // The division by 1 represents the page's default zoom of 100%, - // and gives us the appropriate CSSPixel type for the viewport. - let scaled_viewport_size = viewport_size.to_f32().to_untyped() / device_pixel_ratio; - let window_size = WindowSizeData { - initial_viewport: scaled_viewport_size / Scale::new(1.0), - device_pixel_ratio: Scale::new(device_pixel_ratio), - }; - // Create the constellation, which maintains the engine pipelines, including script and // layout, as well as the navigation context. let mut protocols = ProtocolRegistry::with_internal_protocols(); @@ -476,7 +464,6 @@ impl Servo { #[cfg(feature = "webxr")] webxr_main_thread.registry(), Some(webgl_threads), - window_size, external_images, #[cfg(feature = "webgpu")] wgpu_image_map, @@ -654,8 +641,12 @@ impl Servo { self.webviews .borrow_mut() .insert(webview.id(), webview.weak_handle()); - self.constellation_proxy - .send(ConstellationMsg::NewWebView(url.into(), webview.id())); + let viewport_details = self.compositor.borrow().default_webview_viewport_details(); + self.constellation_proxy.send(ConstellationMsg::NewWebView( + url.into(), + webview.id(), + viewport_details, + )); webview } @@ -724,8 +715,19 @@ impl Servo { }, EmbedderMsg::AllowOpeningWebView(webview_id, response_sender) => { if let Some(webview) = self.get_webview_handle(webview_id) { - let new_webview = webview.delegate().request_open_auxiliary_webview(webview); - let _ = response_sender.send(new_webview.map(|webview| webview.id())); + 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) + }); + let _ = response_sender.send(webview_id_and_viewport_details); } }, EmbedderMsg::WebViewClosed(webview_id) => { @@ -1042,7 +1044,6 @@ fn create_constellation( webrender_api_sender: RenderApiSender, #[cfg(feature = "webxr")] webxr_registry: webxr_api::Registry, webgl_threads: Option<WebGLThreads>, - initial_window_size: WindowSizeData, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, #[cfg(feature = "webgpu")] wgpu_image_map: WGPUImageMap, protocols: ProtocolRegistry, @@ -1105,7 +1106,6 @@ fn create_constellation( Constellation::<script::ScriptThread, script::ServiceWorkerManager>::start( initial_state, layout_factory, - initial_window_size, opts.random_pipeline_closure_probability, opts.random_pipeline_closure_seed, opts.hard_fail, diff --git a/components/shared/constellation/lib.rs b/components/shared/constellation/lib.rs index 38013398dd6..1861de20e52 100644 --- a/components/shared/constellation/lib.rs +++ b/components/shared/constellation/lib.rs @@ -17,17 +17,18 @@ use base::Epoch; use base::cross_process_instant::CrossProcessInstant; use base::id::{PipelineId, ScrollTreeNodeId, WebViewId}; use bitflags::bitflags; -use embedder_traits::{Cursor, InputEvent, MediaSessionActionType, Theme, WebDriverCommandMsg}; -use euclid::{Scale, Size2D, Vector2D}; +use embedder_traits::{ + Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails, WebDriverCommandMsg, +}; +use euclid::Vector2D; use ipc_channel::ipc::IpcSender; use malloc_size_of::malloc_size_of_is_0; use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use servo_url::ServoUrl; use strum_macros::IntoStaticStr; -use style_traits::CSSPixel; use webrender_api::ExternalScrollId; -use webrender_api::units::{DevicePixel, LayoutPixel}; +use webrender_api::units::LayoutPixel; /// Messages to the constellation. #[derive(IntoStaticStr)] @@ -47,8 +48,8 @@ pub enum ConstellationMsg { ClearCache, /// Request to traverse the joint session history of the provided browsing context. TraverseHistory(WebViewId, TraversalDirection), - /// Inform the constellation of a window being resized. - WindowSize(WebViewId, WindowSizeData, WindowSizeType), + /// Inform the Constellation that a `WebView`'s [`ViewportDetails`] have changed. + ChangeViewportDetails(WebViewId, ViewportDetails, WindowSizeType), /// Inform the constellation of a theme change. ThemeChange(Theme), /// Requests that the constellation instruct layout to begin a new tick of the animation. @@ -60,7 +61,7 @@ pub enum ConstellationMsg { /// A log entry, with the top-level browsing context id and thread name LogEntry(Option<WebViewId>, Option<String>, LogEntry), /// Create a new top level browsing context. - NewWebView(ServoUrl, WebViewId), + NewWebView(ServoUrl, WebViewId, ViewportDetails), /// Close a top level browsing context. CloseWebView(WebViewId), /// Panic a top level browsing context. @@ -115,17 +116,6 @@ pub enum LogEntry { Warn(String), } -/// Data about the window size. -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] -pub struct WindowSizeData { - /// The size of the initial layout viewport, before parsing an - /// <http://www.w3.org/TR/css-device-adapt/#initial-viewport> - pub initial_viewport: Size2D<f32, CSSPixel>, - - /// The resolution of the window in dppx, not including any "pinch zoom" factor. - pub device_pixel_ratio: Scale<f32, CSSPixel, DevicePixel>, -} - /// The type of window size change. #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] pub enum WindowSizeType { diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index f617b37d705..67ccd9887ae 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -19,6 +19,7 @@ use std::sync::Arc; use base::id::{PipelineId, WebViewId}; use crossbeam_channel::Sender; +use euclid::{Scale, Size2D}; use http::{HeaderMap, Method, StatusCode}; use ipc_channel::ipc::IpcSender; pub use keyboard_types::{KeyboardEvent, Modifiers}; @@ -29,8 +30,9 @@ use pixels::Image; use serde::{Deserialize, Serialize}; use servo_url::ServoUrl; use strum_macros::IntoStaticStr; +use style_traits::CSSPixel; use url::Url; -use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; +use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel}; pub use crate::input_events::*; pub use crate::webdriver::*; @@ -224,7 +226,6 @@ pub enum AllowOrDeny { } #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct SelectElementOption { /// A unique identifier for the option that can be used to select it. pub id: usize, @@ -244,6 +245,18 @@ pub enum SelectElementOptionOrOptgroup { }, } +/// Data about a `WebView` or `<iframe>` viewport: its size and also the +/// HiDPI scale factor to use when rendering the contents. +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)] +pub struct ViewportDetails { + /// The size of the layout viewport. + pub size: Size2D<f32, CSSPixel>, + + /// The scale factor to use to account for HiDPI scaling. This does not take into account + /// any page or pinch zoom applied by the compositor to the contents. + pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>, +} + #[derive(Deserialize, IntoStaticStr, Serialize)] pub enum EmbedderMsg { /// A status message to be displayed by the browser chrome. @@ -275,7 +288,7 @@ pub enum EmbedderMsg { /// Whether or not to allow a pipeline to load a url. AllowNavigationRequest(WebViewId, PipelineId, ServoUrl), /// Whether or not to allow script to open a new tab/browser - AllowOpeningWebView(WebViewId, IpcSender<Option<WebViewId>>), + AllowOpeningWebView(WebViewId, IpcSender<Option<(WebViewId, ViewportDetails)>>), /// A webview was destroyed. WebViewClosed(WebViewId), /// A webview gained focus for keyboard events. diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 5f9c0eec777..8b4f2ca9966 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -27,13 +27,13 @@ use base::id::{ use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; use constellation_traits::{ - AnimationTickType, CompositorHitTestResult, ScrollState, WindowSizeData, WindowSizeType, + AnimationTickType, CompositorHitTestResult, ScrollState, WindowSizeType, }; use crossbeam_channel::{RecvTimeoutError, Sender}; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use embedder_traits::input_events::InputEvent; use embedder_traits::user_content_manager::UserContentManager; -use embedder_traits::{MediaSessionActionType, Theme, WebDriverScriptCommand}; +use embedder_traits::{MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand}; use euclid::{Rect, Scale, Size2D, UnknownUnit}; use http::{HeaderMap, Method}; use ipc_channel::Error as IpcError; @@ -176,8 +176,8 @@ pub struct NewLayoutInfo { pub opener: Option<BrowsingContextId>, /// Network request data which will be initiated by the script thread. pub load_data: LoadData, - /// Information about the initial window size. - pub window_size: WindowSizeData, + /// Initial [`ViewportDetails`] for this layout. + pub viewport_details: ViewportDetails, } /// When a pipeline is closed, should its browsing context be discarded too? @@ -252,11 +252,11 @@ pub enum ScriptThreadMessage { /// Gives a channel and ID to a layout, as well as the ID of that layout's parent AttachLayout(NewLayoutInfo), /// Window resized. Sends a DOM event eventually, but first we combine events. - Resize(PipelineId, WindowSizeData, WindowSizeType), + Resize(PipelineId, ViewportDetails, WindowSizeType), /// Theme changed. ThemeChange(PipelineId, Theme), /// Notifies script that window has been resized but to not take immediate action. - ResizeInactive(PipelineId, WindowSizeData), + ResizeInactive(PipelineId, ViewportDetails), /// Window switched from fullscreen mode. ExitFullScreen(PipelineId), /// Notifies the script that the document associated with this pipeline should 'unload'. @@ -447,8 +447,8 @@ pub struct InitialScriptState { pub memory_profiler_sender: mem::ProfilerChan, /// A channel to the developer tools, if applicable. pub devtools_server_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - /// Information about the initial window size. - pub window_size: WindowSizeData, + /// Initial [`ViewportDetails`] for the frame that is initiating this `ScriptThread`. + pub viewport_details: ViewportDetails, /// The ID of the pipeline namespace for this script thread. pub pipeline_namespace_id: PipelineNamespaceId, /// A ping will be sent on this channel once the script thread shuts down. @@ -537,7 +537,7 @@ pub struct IFrameLoadInfoWithData { /// Sandbox type of this iframe pub sandbox: IFrameSandboxState, /// The initial viewport size for this iframe. - pub window_size: WindowSizeData, + pub viewport_details: ViewportDetails, } /// Resources required by workerglobalscopes diff --git a/components/shared/script/script_msg.rs b/components/shared/script/script_msg.rs index 8baf158312c..9d03ce2509c 100644 --- a/components/shared/script/script_msg.rs +++ b/components/shared/script/script_msg.rs @@ -13,8 +13,9 @@ use base::id::{ use canvas_traits::canvas::{CanvasId, CanvasMsg}; use constellation_traits::{LogEntry, TraversalDirection}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; -use embedder_traits::{EmbedderMsg, MediaSessionEvent, TouchEventType, TouchSequenceId}; -use euclid::Size2D; +use embedder_traits::{ + EmbedderMsg, MediaSessionEvent, TouchEventType, TouchSequenceId, ViewportDetails, +}; use euclid::default::Size2D as UntypedSize2D; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use net_traits::CoreResourceMsg; @@ -22,7 +23,6 @@ use net_traits::storage_thread::StorageType; use serde::{Deserialize, Serialize}; use servo_url::{ImmutableOrigin, ServoUrl}; use strum_macros::IntoStaticStr; -use style_traits::CSSPixel; #[cfg(feature = "webgpu")] use webgpu_traits::{WebGPU, WebGPUAdapterResponse}; use webrender_api::ImageKey; @@ -39,8 +39,8 @@ use crate::{ pub struct IFrameSizeMsg { /// The child browsing context for this iframe. pub browsing_context_id: BrowsingContextId, - /// The size of the iframe. - pub size: Size2D<f32, CSSPixel>, + /// The size and scale factor of the iframe. + pub size: ViewportDetails, /// The kind of sizing operation. pub type_: WindowSizeType, } diff --git a/components/shared/script_layout/Cargo.toml b/components/shared/script_layout/Cargo.toml index 13d50e4fafe..5c0b6e01d36 100644 --- a/components/shared/script_layout/Cargo.toml +++ b/components/shared/script_layout/Cargo.toml @@ -17,6 +17,7 @@ app_units = { workspace = true } atomic_refcell = { workspace = true } canvas_traits = { workspace = true } constellation_traits = { workspace = true } +embedder_traits = { workspace = true } euclid = { workspace = true } fnv = { workspace = true } fonts = { path = "../../fonts" } diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 817ddd820bd..66ddb3a55fa 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -18,8 +18,8 @@ use app_units::Au; use atomic_refcell::AtomicRefCell; use base::Epoch; use base::id::{BrowsingContextId, PipelineId, WebViewId}; -use constellation_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData}; -use euclid::Size2D; +use constellation_traits::{ScrollState, UntrustedNodeAddress}; +use embedder_traits::ViewportDetails; use euclid::default::{Point2D, Rect}; use fnv::FnvHashMap; use fonts::{FontContext, SystemFontServiceProxy}; @@ -47,7 +47,6 @@ use style::properties::style_structs::Font; use style::queries::values::PrefersColorScheme; use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot}; use style::stylesheets::Stylesheet; -use style_traits::CSSPixel; use webrender_api::ImageKey; use webrender_traits::CrossProcessCompositorApi; @@ -185,7 +184,7 @@ pub struct LayoutConfig { pub font_context: Arc<FontContext>, pub time_profiler_chan: time::ProfilerChan, pub compositor_api: CrossProcessCompositorApi, - pub window_size: WindowSizeData, + pub viewport_details: ViewportDetails, } pub trait LayoutFactory: Send + Sync { @@ -386,7 +385,7 @@ pub struct Reflow { pub struct IFrameSize { pub browsing_context_id: BrowsingContextId, pub pipeline_id: PipelineId, - pub size: Size2D<f32, CSSPixel>, + pub viewport_details: ViewportDetails, } pub type IFrameSizes = FnvHashMap<BrowsingContextId, IFrameSize>; @@ -415,8 +414,8 @@ pub struct ReflowRequest { pub dirty_root: Option<TrustedNodeAddress>, /// Whether the document's stylesheets have changed since the last script reflow. pub stylesheets_changed: bool, - /// The current window size. - pub window_size: WindowSizeData, + /// The current [`ViewportDetails`] to use for this reflow. + pub viewport_details: ViewportDetails, /// The goal of this reflow. pub reflow_goal: ReflowGoal, /// The number of objects in the dom #10110 |