mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Initial internal support for multiple webviews (#31417)
* Add multiple concurrent top-level browsing contexts Co-authored-by: Delan Azabani <dazabani@igalia.com> * Rename variables and comments There are some variable and comments still use browser as names. This commit renames them to webview. * Update log message from web view to webview * Revert offscreen_framebuffer_id rename * Rename all web view to webview * Cargo fmt * Fix viewport/event/clear coordinates when multiview is disabled * Only deprecate things when multiview is enabled * Update WebViewManger with shown and invisible sets Replace visible_webviews and native_window_is_visible with shown_webviews and invisible_webviews. Add 4 more methods to set them accordingly. The behavior of is_effectively_visible will return true if the wbview is in shown_webviews set but not in invisible_webviews. * Update variant behaviors * Rename WebViewVisibilityChanged to MarkWebViewInvisible * Fix unit test by marking id 3 visible again * Update MarkWebViewInvisible and add UnmarkWebViewInvisible * Update format and doc comments * Clean up doc comments * Address style and naming changes * Rename UpdateWebView to UpdateFrameTreeForWebView * constellation: send frame tree unconditionally over focus and feature * Clarify shown and invisible sets in constellation WebViewManager * Eliminate forward_to_constellation!() * Actually remove the unused macro * Don’t gate compositor changes on multiview feature flag * Update todo in mouse event dispatch * Pass all visible webview ids in a single ReadyToPresent message * Fix compile and lint errors * servoshell: fix gap between minibrowser toolbar and webview * Fix failure in /_mozilla/mozilla/window_resizeTo.html * Fix compile warnings * Remove stray dbg!() * Remove confusing “effectively visible” logic (see #31815, #31816) * Allow embedder to show/hide/raise webviews without ipc * Update root pipeline only when painting order actually changes * Stop gating old focus and SetFrameTree behaviour behind Cargo feature * Use webview_id and WebViewId in webview-related code * Improve logging of webview-related embedder events * Allow webview Show and Raise events to optionally hide all others * Don’t do anything in response to WebViewPaintingOrder * Remove WebViewPaintingOrder, since its payload is unreliable * On MoveResizeWebView, only update root pipeline if rect changed * Rename IOCompositor methods for clarity * compositor: add event tracing; log webview ops even without ipc * Add temporary debug logging * Add more temporary debug logging * Remove temporary logging in compositor * Remove temporary debug logging * Add temporary debug logging, but defer I/O until panic * Capture a backtrace with each crash log entry * Proper error handling without panicking in WebViewManager * Clean up imports in constellation --------- Co-authored-by: Delan Azabani <dazabani@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
18b37e676b
commit
66878fb834
21 changed files with 1142 additions and 434 deletions
|
@ -7,6 +7,7 @@ use std::collections::HashMap;
|
|||
use std::env;
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::Write;
|
||||
use std::iter::once;
|
||||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
|
@ -27,7 +28,7 @@ use ipc_channel::ipc;
|
|||
use libc::c_void;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use msg::constellation_msg::{
|
||||
PipelineId, PipelineIndex, PipelineNamespaceId, TopLevelBrowsingContextId,
|
||||
PipelineId, PipelineIndex, PipelineNamespaceId, TopLevelBrowsingContextId, WebViewId,
|
||||
};
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image_cache::CorsStatus;
|
||||
|
@ -44,7 +45,7 @@ use servo_geometry::{DeviceIndependentPixel, FramebufferUintLength};
|
|||
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
||||
use webrender::{CaptureBits, RenderApi, Transaction};
|
||||
use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutPoint, LayoutRect, LayoutSize,
|
||||
DeviceIntPoint, DeviceIntSize, DevicePoint, DeviceRect, LayoutPoint, LayoutRect, LayoutSize,
|
||||
LayoutVector2D, WorldPoint,
|
||||
};
|
||||
use webrender_api::{
|
||||
|
@ -56,6 +57,7 @@ use webrender_api::{
|
|||
|
||||
use crate::gl::RenderTargetInfo;
|
||||
use crate::touch::{TouchAction, TouchHandler};
|
||||
use crate::webview::{UnknownWebView, WebView, WebViewAlreadyExists, WebViewManager};
|
||||
use crate::windowing::{
|
||||
self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods,
|
||||
};
|
||||
|
@ -109,11 +111,6 @@ impl FrameTreeId {
|
|||
}
|
||||
}
|
||||
|
||||
struct RootPipeline {
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
id: Option<PipelineId>,
|
||||
}
|
||||
|
||||
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
|
||||
pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
||||
/// The application window.
|
||||
|
@ -122,10 +119,8 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
|||
/// The port on which we receive messages.
|
||||
port: CompositorReceiver,
|
||||
|
||||
/// The root content pipeline ie the pipeline which contains the main frame
|
||||
/// to display. In the WebRender scene, this will be the only child of another
|
||||
/// pipeline which applies a pinch zoom transformation.
|
||||
root_content_pipeline: RootPipeline,
|
||||
/// Our top-level browsing contexts.
|
||||
webviews: WebViewManager<WebView>,
|
||||
|
||||
/// Tracks details about each active pipeline that the compositor knows about.
|
||||
pipeline_details: HashMap<PipelineId, PipelineDetails>,
|
||||
|
@ -292,6 +287,9 @@ struct PipelineDetails {
|
|||
/// The pipeline associated with this PipelineDetails object.
|
||||
pipeline: Option<CompositionPipeline>,
|
||||
|
||||
/// The id of the parent pipeline, if any.
|
||||
parent_pipeline_id: Option<PipelineId>,
|
||||
|
||||
/// The epoch of the most recent display list for this pipeline. Note that this display
|
||||
/// list might not be displayed, as WebRender processes display lists asynchronously.
|
||||
most_recent_display_list_epoch: Option<WebRenderEpoch>,
|
||||
|
@ -318,6 +316,7 @@ impl PipelineDetails {
|
|||
fn new() -> PipelineDetails {
|
||||
PipelineDetails {
|
||||
pipeline: None,
|
||||
parent_pipeline_id: None,
|
||||
most_recent_display_list_epoch: None,
|
||||
animations_running: false,
|
||||
animation_callbacks_running: false,
|
||||
|
@ -376,14 +375,26 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
convert_mouse_to_touch: bool,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
) -> Self {
|
||||
let embedder_coordinates = window.get_coordinates();
|
||||
let mut webviews = WebViewManager::default();
|
||||
webviews
|
||||
.add(
|
||||
top_level_browsing_context_id,
|
||||
WebView {
|
||||
pipeline_id: None,
|
||||
rect: embedder_coordinates.get_viewport().to_f32(),
|
||||
},
|
||||
)
|
||||
.expect("Infallible with a new WebViewManager");
|
||||
webviews
|
||||
.show(top_level_browsing_context_id)
|
||||
.expect("Infallible due to add");
|
||||
|
||||
IOCompositor {
|
||||
embedder_coordinates: window.get_coordinates(),
|
||||
window,
|
||||
port: state.receiver,
|
||||
root_content_pipeline: RootPipeline {
|
||||
top_level_browsing_context_id,
|
||||
id: None,
|
||||
},
|
||||
webviews,
|
||||
pipeline_details: HashMap::new(),
|
||||
composition_request: CompositionRequest::NoCompositingNecessary,
|
||||
touch_handler: TouchHandler::new(),
|
||||
|
@ -524,6 +535,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn handle_browser_message(&mut self, msg: CompositorMsg) -> bool {
|
||||
trace_msg_from_constellation!(msg, "{msg:?}");
|
||||
|
||||
match self.shutdown_state {
|
||||
ShutdownState::NotShuttingDown => {},
|
||||
ShutdownState::ShuttingDown => {
|
||||
|
@ -546,11 +559,40 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
self.change_running_animations_state(pipeline_id, animation_state);
|
||||
},
|
||||
|
||||
CompositorMsg::SetFrameTree(frame_tree) => {
|
||||
self.set_frame_tree(&frame_tree);
|
||||
CompositorMsg::CreateOrUpdateWebView(frame_tree) => {
|
||||
self.set_frame_tree_for_webview(&frame_tree);
|
||||
self.send_scroll_positions_to_layout_for_pipeline(&frame_tree.pipeline.id);
|
||||
},
|
||||
|
||||
CompositorMsg::RemoveWebView(top_level_browsing_context_id) => {
|
||||
self.remove_webview(top_level_browsing_context_id);
|
||||
},
|
||||
|
||||
CompositorMsg::MoveResizeWebView(webview_id, rect) => {
|
||||
self.move_resize_webview(webview_id, rect);
|
||||
},
|
||||
|
||||
CompositorMsg::ShowWebView(webview_id, hide_others) => {
|
||||
if let Err(UnknownWebView(webview_id)) = self.show_webview(webview_id, hide_others)
|
||||
{
|
||||
warn!("{webview_id}: ShowWebView on unknown webview id");
|
||||
}
|
||||
},
|
||||
|
||||
CompositorMsg::HideWebView(webview_id) => {
|
||||
if let Err(UnknownWebView(webview_id)) = self.hide_webview(webview_id) {
|
||||
warn!("{webview_id}: HideWebView on unknown webview id");
|
||||
}
|
||||
},
|
||||
|
||||
CompositorMsg::RaiseWebViewToTop(webview_id, hide_others) => {
|
||||
if let Err(UnknownWebView(webview_id)) =
|
||||
self.raise_webview_to_top(webview_id, hide_others)
|
||||
{
|
||||
warn!("{webview_id}: RaiseWebViewToTop on unknown webview id");
|
||||
}
|
||||
},
|
||||
|
||||
CompositorMsg::TouchEventProcessed(result) => {
|
||||
self.touch_handler.on_event_processed(result);
|
||||
},
|
||||
|
@ -1016,16 +1058,21 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set the root pipeline for our WebRender scene. If there is no pinch zoom applied,
|
||||
/// the root pipeline is the root content pipeline. If there is pinch zoom, the root
|
||||
/// content pipeline is wrapped in a display list that applies a pinch zoom
|
||||
/// transformation to it.
|
||||
fn set_root_content_pipeline_handling_device_scaling(&self, transaction: &mut Transaction) {
|
||||
let root_content_pipeline = match self.root_content_pipeline.id {
|
||||
Some(id) => id.to_webrender(),
|
||||
None => return,
|
||||
};
|
||||
/// Set the root pipeline for our WebRender scene to a display list that consists of an iframe
|
||||
/// for each visible top-level browsing context, applying a transformation on the root for
|
||||
/// pinch zoom, page zoom, and HiDPI scaling.
|
||||
fn send_root_pipeline_display_list(&mut self) {
|
||||
let mut transaction = Transaction::new();
|
||||
self.send_root_pipeline_display_list_in_transaction(&mut transaction);
|
||||
self.generate_frame(&mut transaction, RenderReasons::SCENE);
|
||||
self.webrender_api
|
||||
.send_transaction(self.webrender_document, transaction);
|
||||
}
|
||||
|
||||
/// Set the root pipeline for our WebRender scene to a display list that consists of an iframe
|
||||
/// for each visible top-level browsing context, applying a transformation on the root for
|
||||
/// pinch zoom, page zoom, and HiDPI scaling.
|
||||
fn send_root_pipeline_display_list_in_transaction(&self, transaction: &mut Transaction) {
|
||||
// Every display list needs a pipeline, but we'd like to choose one that is unlikely
|
||||
// to conflict with our content pipelines, which start at (1, 1). (0, 0) is WebRender's
|
||||
// dummy pipeline, so we choose (0, 1).
|
||||
|
@ -1034,10 +1081,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
|
||||
let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline);
|
||||
builder.begin();
|
||||
let viewport_size = LayoutSize::new(
|
||||
self.embedder_coordinates.get_viewport().width() as f32,
|
||||
self.embedder_coordinates.get_viewport().height() as f32,
|
||||
);
|
||||
|
||||
let zoom_factor = self.device_pixels_per_page_pixel().0;
|
||||
let zoom_reference_frame = builder.push_reference_frame(
|
||||
|
@ -1053,26 +1096,30 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
SpatialTreeItemKey::new(0, 0),
|
||||
);
|
||||
|
||||
let scaled_viewport_rect = LayoutRect::from_origin_and_size(
|
||||
LayoutPoint::zero(),
|
||||
LayoutSize::new(
|
||||
viewport_size.width / zoom_factor,
|
||||
viewport_size.height / zoom_factor,
|
||||
),
|
||||
);
|
||||
let scaled_viewport_size =
|
||||
self.embedder_coordinates.get_viewport().size().to_f32() / zoom_factor;
|
||||
let scaled_viewport_size = LayoutSize::from_untyped(scaled_viewport_size.to_untyped());
|
||||
let scaled_viewport_rect =
|
||||
LayoutRect::from_origin_and_size(LayoutPoint::zero(), scaled_viewport_size);
|
||||
|
||||
let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect);
|
||||
let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
|
||||
builder.push_iframe(
|
||||
scaled_viewport_rect,
|
||||
scaled_viewport_rect,
|
||||
&SpaceAndClipInfo {
|
||||
spatial_id: zoom_reference_frame,
|
||||
clip_chain_id,
|
||||
},
|
||||
root_content_pipeline,
|
||||
true,
|
||||
);
|
||||
for (_, webview) in self.webviews.painting_order() {
|
||||
if let Some(pipeline_id) = webview.pipeline_id {
|
||||
let scaled_webview_rect = webview.rect / zoom_factor;
|
||||
builder.push_iframe(
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
&SpaceAndClipInfo {
|
||||
spatial_id: zoom_reference_frame,
|
||||
clip_chain_id,
|
||||
},
|
||||
pipeline_id.to_webrender(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let built_display_list = builder.end();
|
||||
|
||||
// NB: We are always passing 0 as the epoch here, but this doesn't seem to
|
||||
|
@ -1109,29 +1156,163 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
|
||||
debug!(
|
||||
"Setting the frame tree for pipeline {:?}",
|
||||
frame_tree.pipeline.id
|
||||
);
|
||||
fn set_frame_tree_for_webview(&mut self, frame_tree: &SendableFrameTree) {
|
||||
debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
|
||||
|
||||
self.root_content_pipeline = RootPipeline {
|
||||
top_level_browsing_context_id: frame_tree.pipeline.top_level_browsing_context_id,
|
||||
id: Some(frame_tree.pipeline.id),
|
||||
};
|
||||
let top_level_browsing_context_id = frame_tree.pipeline.top_level_browsing_context_id;
|
||||
if let Some(webview) = self.webviews.get_mut(top_level_browsing_context_id) {
|
||||
let new_pipeline_id = Some(frame_tree.pipeline.id);
|
||||
if new_pipeline_id != webview.pipeline_id {
|
||||
debug!(
|
||||
"{:?}: Updating webview from pipeline {:?} to {:?}",
|
||||
top_level_browsing_context_id, webview.pipeline_id, new_pipeline_id
|
||||
);
|
||||
}
|
||||
webview.pipeline_id = new_pipeline_id;
|
||||
} else {
|
||||
let top_level_browsing_context_id = frame_tree.pipeline.top_level_browsing_context_id;
|
||||
let pipeline_id = Some(frame_tree.pipeline.id);
|
||||
debug!(
|
||||
"{:?}: Creating new webview with pipeline {:?}",
|
||||
top_level_browsing_context_id, pipeline_id
|
||||
);
|
||||
if let Err(WebViewAlreadyExists(webview_id)) = self.webviews.add(
|
||||
top_level_browsing_context_id,
|
||||
WebView {
|
||||
pipeline_id,
|
||||
rect: self.embedder_coordinates.get_viewport().to_f32(),
|
||||
},
|
||||
) {
|
||||
error!("{webview_id}: Creating webview that already exists");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut txn = Transaction::new();
|
||||
self.set_root_content_pipeline_handling_device_scaling(&mut txn);
|
||||
self.generate_frame(&mut txn, RenderReasons::SCENE);
|
||||
self.webrender_api
|
||||
.send_transaction(self.webrender_document, txn);
|
||||
|
||||
self.create_pipeline_details_for_frame_tree(frame_tree);
|
||||
self.reset_scroll_tree_for_unattached_pipelines(frame_tree);
|
||||
self.send_root_pipeline_display_list();
|
||||
self.create_or_update_pipeline_details_with_frame_tree(&frame_tree, None);
|
||||
self.reset_scroll_tree_for_unattached_pipelines(&frame_tree);
|
||||
|
||||
self.frame_tree_id.next();
|
||||
}
|
||||
|
||||
fn remove_webview(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) {
|
||||
debug!("{}: Removing", top_level_browsing_context_id);
|
||||
let Ok(webview) = self.webviews.remove(top_level_browsing_context_id) else {
|
||||
warn!("{top_level_browsing_context_id}: Removing unknown webview");
|
||||
return;
|
||||
};
|
||||
|
||||
self.send_root_pipeline_display_list();
|
||||
if let Some(pipeline_id) = webview.pipeline_id {
|
||||
self.remove_pipeline_details_recursively(pipeline_id);
|
||||
}
|
||||
|
||||
self.frame_tree_id.next();
|
||||
}
|
||||
|
||||
pub fn move_resize_webview(&mut self, webview_id: TopLevelBrowsingContextId, rect: DeviceRect) {
|
||||
debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}");
|
||||
let rect_changed;
|
||||
let size_changed;
|
||||
match self.webviews.get_mut(webview_id) {
|
||||
Some(webview) => {
|
||||
rect_changed = rect != webview.rect;
|
||||
size_changed = rect.size() != webview.rect.size();
|
||||
webview.rect = rect;
|
||||
},
|
||||
None => {
|
||||
warn!("{webview_id}: MoveResizeWebView on unknown webview id");
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
if rect_changed {
|
||||
if size_changed {
|
||||
self.send_window_size_message_for_top_level_browser_context(rect, webview_id);
|
||||
}
|
||||
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_webview(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
hide_others: bool,
|
||||
) -> Result<(), UnknownWebView> {
|
||||
debug!("{webview_id}: Showing webview; hide_others={hide_others}");
|
||||
let painting_order_changed = if hide_others {
|
||||
let result = self
|
||||
.webviews
|
||||
.painting_order()
|
||||
.map(|(&id, _)| id)
|
||||
.ne(once(webview_id));
|
||||
self.webviews.hide_all();
|
||||
self.webviews.show(webview_id)?;
|
||||
result
|
||||
} else {
|
||||
self.webviews.show(webview_id)?
|
||||
};
|
||||
if painting_order_changed {
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
|
||||
debug!("{webview_id}: Hiding webview");
|
||||
if self.webviews.hide(webview_id)? {
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn raise_webview_to_top(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
hide_others: bool,
|
||||
) -> Result<(), UnknownWebView> {
|
||||
debug!("{webview_id}: Raising webview to top; hide_others={hide_others}");
|
||||
let painting_order_changed = if hide_others {
|
||||
let result = self
|
||||
.webviews
|
||||
.painting_order()
|
||||
.map(|(&id, _)| id)
|
||||
.ne(once(webview_id));
|
||||
self.webviews.hide_all();
|
||||
self.webviews.raise_to_top(webview_id)?;
|
||||
result
|
||||
} else {
|
||||
self.webviews.raise_to_top(webview_id)?
|
||||
};
|
||||
if painting_order_changed {
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_window_size_message_for_top_level_browser_context(
|
||||
&self,
|
||||
rect: DeviceRect,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
) {
|
||||
// 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(
|
||||
top_level_browsing_context_id,
|
||||
WindowSizeData {
|
||||
device_pixel_ratio,
|
||||
initial_viewport,
|
||||
},
|
||||
WindowSizeType::Resize,
|
||||
);
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending window resize to constellation failed ({:?}).", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_scroll_tree_for_unattached_pipelines(&mut self, frame_tree: &SendableFrameTree) {
|
||||
// TODO(mrobinson): Eventually this can selectively preserve the scroll trees
|
||||
// state for some unattached pipelines in order to preserve scroll position when
|
||||
|
@ -1159,11 +1340,35 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
})
|
||||
}
|
||||
|
||||
fn create_pipeline_details_for_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
|
||||
self.pipeline_details(frame_tree.pipeline.id).pipeline = Some(frame_tree.pipeline.clone());
|
||||
fn create_or_update_pipeline_details_with_frame_tree(
|
||||
&mut self,
|
||||
frame_tree: &SendableFrameTree,
|
||||
parent_pipeline_id: Option<PipelineId>,
|
||||
) {
|
||||
let pipeline_id = frame_tree.pipeline.id;
|
||||
let pipeline_details = self.pipeline_details(pipeline_id);
|
||||
pipeline_details.pipeline = Some(frame_tree.pipeline.clone());
|
||||
pipeline_details.parent_pipeline_id = parent_pipeline_id;
|
||||
|
||||
for kid in &frame_tree.children {
|
||||
self.create_pipeline_details_for_frame_tree(kid);
|
||||
self.create_or_update_pipeline_details_with_frame_tree(kid, Some(pipeline_id));
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_pipeline_details_recursively(&mut self, pipeline_id: PipelineId) {
|
||||
self.pipeline_details.remove(&pipeline_id);
|
||||
|
||||
let children = self
|
||||
.pipeline_details
|
||||
.iter()
|
||||
.filter(|(_, pipeline_details)| {
|
||||
pipeline_details.parent_pipeline_id == Some(pipeline_id)
|
||||
})
|
||||
.map(|(&pipeline_id, _)| pipeline_id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for kid in children {
|
||||
self.remove_pipeline_details_recursively(kid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1225,9 +1430,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
MouseWindowEvent::MouseUp(_, p) => p,
|
||||
};
|
||||
|
||||
let result = match self.hit_test_at_point(point) {
|
||||
Some(result) => result,
|
||||
None => return,
|
||||
let Some(result) = self.hit_test_at_point(point) else {
|
||||
// TODO: Notify embedder that the event failed to hit test to any webview.
|
||||
// TODO: Also notify embedder if an event hits a webview but isn’t consumed?
|
||||
return;
|
||||
};
|
||||
|
||||
let (button, event_type) = match mouse_window_event {
|
||||
|
@ -1264,13 +1470,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
flags: HitTestFlags,
|
||||
pipeline_id: Option<WebRenderPipelineId>,
|
||||
) -> Vec<CompositorHitTestResult> {
|
||||
let root_pipeline_id = match self.root_content_pipeline.id {
|
||||
Some(root_pipeline_id) => root_pipeline_id,
|
||||
None => return vec![],
|
||||
};
|
||||
if self.pipeline(root_pipeline_id).is_none() {
|
||||
return vec![];
|
||||
}
|
||||
// DevicePoint and WorldPoint are the same for us.
|
||||
let world_point = WorldPoint::from_untyped(point.to_untyped());
|
||||
let results =
|
||||
|
@ -1526,7 +1725,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
|
||||
let mut transaction = Transaction::new();
|
||||
if zoom_changed {
|
||||
self.set_root_content_pipeline_handling_device_scaling(&mut transaction);
|
||||
self.send_root_pipeline_display_list_in_transaction(&mut transaction);
|
||||
}
|
||||
|
||||
if let Some((pipeline_id, external_id, offset)) = scroll_result {
|
||||
|
@ -1670,33 +1869,15 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn update_after_zoom_or_hidpi_change(&mut self) {
|
||||
// The device pixel ratio used by the style system should include the scale from page pixels
|
||||
// to device pixels, but not including any pinch zoom.
|
||||
let device_pixel_ratio = self.device_pixels_per_page_pixel_not_including_page_zoom();
|
||||
let initial_viewport =
|
||||
self.embedder_coordinates.viewport.size().to_f32() / device_pixel_ratio;
|
||||
let data = WindowSizeData {
|
||||
device_pixel_ratio,
|
||||
initial_viewport,
|
||||
};
|
||||
|
||||
let top_level_browsing_context_id =
|
||||
self.root_content_pipeline.top_level_browsing_context_id;
|
||||
|
||||
let msg = ConstellationMsg::WindowSize(
|
||||
top_level_browsing_context_id,
|
||||
data,
|
||||
WindowSizeType::Resize,
|
||||
);
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending window resize to constellation failed ({:?}).", e);
|
||||
for (top_level_browsing_context_id, webview) in self.webviews.painting_order() {
|
||||
self.send_window_size_message_for_top_level_browser_context(
|
||||
webview.rect,
|
||||
*top_level_browsing_context_id,
|
||||
);
|
||||
}
|
||||
|
||||
// Update the root transform in WebRender to reflect the new zoom.
|
||||
let mut transaction = webrender::Transaction::new();
|
||||
self.set_root_content_pipeline_handling_device_scaling(&mut transaction);
|
||||
self.webrender_api
|
||||
.send_transaction(self.webrender_document, transaction);
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
|
||||
/// Simulate a pinch zoom
|
||||
|
@ -1928,6 +2109,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
// and check if it is the one layout is expecting,
|
||||
let epoch = Epoch(epoch);
|
||||
if *pending_epoch != epoch {
|
||||
warn!(
|
||||
"{}: paint metrics: pending {:?} should be {:?}",
|
||||
id, pending_epoch, epoch
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// in which case, we remove it from the list of pending metrics,
|
||||
|
@ -2032,12 +2217,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
},
|
||||
};
|
||||
|
||||
// Nottify embedder that servo is ready to present.
|
||||
// Notify embedder that servo is ready to present.
|
||||
// Embedder should call `present` to tell compositor to continue rendering.
|
||||
self.waiting_on_present = true;
|
||||
let msg = ConstellationMsg::ReadyToPresent(
|
||||
self.root_content_pipeline.top_level_browsing_context_id,
|
||||
);
|
||||
let webview_ids = self.webviews.painting_order().map(|(&id, _)| id);
|
||||
let msg = ConstellationMsg::ReadyToPresent(webview_ids.collect());
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending event to constellation failed ({:?}).", e);
|
||||
}
|
||||
|
@ -2077,14 +2261,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
self.assert_gl_framebuffer_complete();
|
||||
|
||||
// Set the viewport background based on prefs.
|
||||
let viewport = self.embedder_coordinates.get_flipped_viewport();
|
||||
gl.scissor(
|
||||
viewport.min.x,
|
||||
viewport.min.y,
|
||||
viewport.size().width,
|
||||
viewport.size().height,
|
||||
);
|
||||
|
||||
let color = servo_config::pref!(shell.background_color.rgba);
|
||||
gl.clear_color(
|
||||
color[0] as f32,
|
||||
|
@ -2092,9 +2268,21 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
color[2] as f32,
|
||||
color[3] as f32,
|
||||
);
|
||||
gl.enable(gleam::gl::SCISSOR_TEST);
|
||||
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
|
||||
gl.disable(gleam::gl::SCISSOR_TEST);
|
||||
|
||||
// Clear the viewport rect of each top-level browsing context.
|
||||
for (_, webview) in self.webviews.painting_order() {
|
||||
let rect = self.embedder_coordinates.flip_rect(&webview.rect.to_i32());
|
||||
gl.scissor(
|
||||
rect.min.x,
|
||||
rect.min.y,
|
||||
rect.size().width,
|
||||
rect.size().height,
|
||||
);
|
||||
gl.enable(gleam::gl::SCISSOR_TEST);
|
||||
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
|
||||
gl.disable(gleam::gl::SCISSOR_TEST);
|
||||
}
|
||||
|
||||
self.assert_gl_framebuffer_complete();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue