mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
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:
parent
7c89e24f34
commit
fb344ba4e9
26 changed files with 272 additions and 256 deletions
|
@ -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,
|
||||
));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue