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>
This commit is contained in:
Martin Robinson 2025-04-04 19:06:34 +02:00 committed by GitHub
parent 7c89e24f34
commit fb344ba4e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 272 additions and 256 deletions

View file

@ -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 {

View file

@ -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.

View file

@ -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

View file

@ -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,
}

View file

@ -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" }

View file

@ -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