compositing: Split non-WebView-specific data into ServoRenderer (#35536)

This will become the new global Servo renderer while each WebView will
also have its renderer (but not yet).

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Ngo Iok Ui (Wu Yu Wei) <yuweiwu@pm.me>
This commit is contained in:
Martin Robinson 2025-02-19 16:29:32 +01:00 committed by GitHub
parent 4a5ff01e06
commit 168f7ead15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 170 additions and 124 deletions

View file

@ -96,17 +96,50 @@ impl FrameTreeId {
} }
} }
/// NB: Never block on the constellation, because sometimes the constellation blocks on us. /// Data that is shared by all WebView renderers.
pub struct IOCompositor { pub struct ServoRenderer {
/// The application window.
pub window: Rc<dyn WindowMethods>,
/// The port on which we receive messages.
port: CompositorReceiver,
/// Our top-level browsing contexts. /// Our top-level browsing contexts.
webviews: WebViewManager<WebView>, webviews: WebViewManager<WebView>,
/// Tracks whether we are in the process of shutting down, or have shut down and should close
/// the compositor.
shutdown_state: ShutdownState,
/// The port on which we receive messages.
compositor_receiver: CompositorReceiver,
/// The channel on which messages can be sent to the constellation.
constellation_sender: Sender<ConstellationMsg>,
/// The channel on which messages can be sent to the time profiler.
time_profiler_chan: profile_time::ProfilerChan,
/// The WebRender [`RenderApi`] interface used to communicate with WebRender.
webrender_api: RenderApi,
/// The GL bindings for webrender
webrender_gl: Rc<dyn gleam::gl::Gl>,
/// True to exit after page load ('-x').
exit_after_load: bool,
/// The string representing the version of Servo that is running. This is used to tag
/// WebRender capture output.
version_string: String,
#[cfg(feature = "webxr")]
/// Some XR devices want to run on the main thread.
webxr_main_thread: webxr::MainThreadRegistry,
}
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
pub struct IOCompositor {
/// Data that is shared by all WebView renderers.
global: ServoRenderer,
/// The application window.
pub window: Rc<dyn WindowMethods>,
/// Tracks details about each active pipeline that the compositor knows about. /// Tracks details about each active pipeline that the compositor knows about.
pipeline_details: HashMap<PipelineId, PipelineDetails>, pipeline_details: HashMap<PipelineId, PipelineDetails>,
@ -126,10 +159,6 @@ pub struct IOCompositor {
/// Tracks whether or not the view needs to be repainted. /// Tracks whether or not the view needs to be repainted.
needs_repaint: Cell<RepaintReason>, needs_repaint: Cell<RepaintReason>,
/// Tracks whether we are in the process of shutting down, or have shut down and should close
/// the compositor.
pub shutdown_state: ShutdownState,
/// Tracks whether the zoom action has happened recently. /// Tracks whether the zoom action has happened recently.
zoom_action: bool, zoom_action: bool,
@ -139,12 +168,6 @@ pub struct IOCompositor {
/// The current frame tree ID (used to reject old paint buffers) /// The current frame tree ID (used to reject old paint buffers)
frame_tree_id: FrameTreeId, frame_tree_id: FrameTreeId,
/// The channel on which messages can be sent to the constellation.
constellation_chan: Sender<ConstellationMsg>,
/// The channel on which messages can be sent to the time profiler.
time_profiler_chan: profile_time::ProfilerChan,
/// Touch input state machine /// Touch input state machine
touch_handler: TouchHandler, touch_handler: TouchHandler,
@ -161,19 +184,9 @@ pub struct IOCompositor {
/// The active webrender document. /// The active webrender document.
webrender_document: DocumentId, webrender_document: DocumentId,
/// The webrender interface, if enabled.
webrender_api: RenderApi,
/// The surfman instance that webrender targets /// The surfman instance that webrender targets
rendering_context: Rc<dyn RenderingContext>, rendering_context: Rc<dyn RenderingContext>,
/// The GL bindings for webrender
webrender_gl: Rc<dyn gleam::gl::Gl>,
#[cfg(feature = "webxr")]
/// Some XR devices want to run on the main thread.
pub webxr_main_thread: webxr::MainThreadRegistry,
/// A per-pipeline queue of display lists that have not yet been rendered by WebRender. Layout /// A per-pipeline queue of display lists that have not yet been rendered by WebRender. Layout
/// expects WebRender to paint each given epoch. Once the compositor paints a frame with that /// expects WebRender to paint each given epoch. Once the compositor paints a frame with that
/// epoch's display list, it will be removed from the queue and the paint time will be recorded /// epoch's display list, it will be removed from the queue and the paint time will be recorded
@ -190,9 +203,6 @@ pub struct IOCompositor {
/// Current cursor position. /// Current cursor position.
cursor_pos: DevicePoint, cursor_pos: DevicePoint,
/// True to exit after page load ('-x').
exit_after_load: bool,
/// True to translate mouse input into touch events. /// True to translate mouse input into touch events.
convert_mouse_to_touch: bool, convert_mouse_to_touch: bool,
@ -202,10 +212,6 @@ pub struct IOCompositor {
/// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and /// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and
/// ScriptThread with a deluge of animation ticks. /// ScriptThread with a deluge of animation ticks.
last_animation_tick: Instant, last_animation_tick: Instant,
/// The string representing the version of Servo that is running. This is used to tag
/// WebRender capture output.
version_string: String,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -341,16 +347,26 @@ impl IOCompositor {
version_string: String, version_string: String,
) -> Self { ) -> Self {
let compositor = IOCompositor { let compositor = IOCompositor {
global: ServoRenderer {
shutdown_state: ShutdownState::NotShuttingDown,
webviews: WebViewManager::default(),
compositor_receiver: state.receiver,
constellation_sender: state.constellation_chan,
time_profiler_chan: state.time_profiler_chan,
webrender_api: state.webrender_api,
webrender_gl: state.webrender_gl,
exit_after_load,
version_string,
#[cfg(feature = "webxr")]
webxr_main_thread: state.webxr_main_thread,
},
embedder_coordinates: window.get_coordinates(), embedder_coordinates: window.get_coordinates(),
window, window,
port: state.receiver,
webviews: WebViewManager::default(),
pipeline_details: HashMap::new(), pipeline_details: HashMap::new(),
needs_repaint: Cell::default(), needs_repaint: Cell::default(),
touch_handler: TouchHandler::new(), touch_handler: TouchHandler::new(),
pending_scroll_zoom_events: Vec::new(), pending_scroll_zoom_events: Vec::new(),
composite_target, composite_target,
shutdown_state: ShutdownState::NotShuttingDown,
page_zoom: Scale::new(1.0), page_zoom: Scale::new(1.0),
viewport_zoom: PinchZoomFactor::new(1.0), viewport_zoom: PinchZoomFactor::new(1.0),
min_viewport_zoom: Some(PinchZoomFactor::new(1.0)), min_viewport_zoom: Some(PinchZoomFactor::new(1.0)),
@ -358,33 +374,29 @@ impl IOCompositor {
zoom_action: false, zoom_action: false,
zoom_time: 0f64, zoom_time: 0f64,
frame_tree_id: FrameTreeId(0), frame_tree_id: FrameTreeId(0),
constellation_chan: state.constellation_chan,
time_profiler_chan: state.time_profiler_chan,
ready_to_save_state: ReadyState::Unknown, ready_to_save_state: ReadyState::Unknown,
webrender: Some(state.webrender), webrender: Some(state.webrender),
webrender_document: state.webrender_document, webrender_document: state.webrender_document,
webrender_api: state.webrender_api,
rendering_context: state.rendering_context, rendering_context: state.rendering_context,
webrender_gl: state.webrender_gl,
#[cfg(feature = "webxr")]
webxr_main_thread: state.webxr_main_thread,
pending_paint_metrics: HashMap::new(), pending_paint_metrics: HashMap::new(),
cursor: Cursor::None, cursor: Cursor::None,
cursor_pos: DevicePoint::new(0.0, 0.0), cursor_pos: DevicePoint::new(0.0, 0.0),
exit_after_load,
convert_mouse_to_touch, convert_mouse_to_touch,
pending_frames: 0, pending_frames: 0,
last_animation_tick: Instant::now(), last_animation_tick: Instant::now(),
version_string,
}; };
let gl = &compositor.webrender_gl; let gl = &compositor.global.webrender_gl;
info!("Running on {}", gl.get_string(gleam::gl::RENDERER)); info!("Running on {}", gl.get_string(gleam::gl::RENDERER));
info!("OpenGL Version {}", gl.get_string(gleam::gl::VERSION)); info!("OpenGL Version {}", gl.get_string(gleam::gl::VERSION));
compositor.assert_gl_framebuffer_complete(); compositor.assert_gl_framebuffer_complete();
compositor compositor
} }
pub fn shutdown_state(&self) -> ShutdownState {
self.global.shutdown_state
}
pub fn deinit(&mut self) { pub fn deinit(&mut self) {
if let Err(err) = self.rendering_context.make_current() { if let Err(err) = self.rendering_context.make_current() {
warn!("Failed to make the rendering context current: {:?}", err); warn!("Failed to make the rendering context current: {:?}", err);
@ -424,23 +436,27 @@ impl IOCompositor {
self.cursor = cursor; self.cursor = cursor;
let msg = ConstellationMsg::SetCursor(webview_id, cursor); let msg = ConstellationMsg::SetCursor(webview_id, cursor);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e); warn!("Sending event to constellation failed ({:?}).", e);
} }
} }
pub fn start_shutting_down(&mut self) { pub fn start_shutting_down(&mut self) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
warn!("Requested shutdown while already shutting down"); warn!("Requested shutdown while already shutting down");
return; return;
} }
debug!("Compositor sending Exit message to Constellation"); debug!("Compositor sending Exit message to Constellation");
if let Err(e) = self.constellation_chan.send(ConstellationMsg::Exit) { if let Err(e) = self
.global
.constellation_sender
.send(ConstellationMsg::Exit)
{
warn!("Sending exit message to constellation failed ({:?}).", e); warn!("Sending exit message to constellation failed ({:?}).", e);
} }
self.shutdown_state = ShutdownState::ShuttingDown; self.global.shutdown_state = ShutdownState::ShuttingDown;
} }
fn finish_shutting_down(&mut self) { fn finish_shutting_down(&mut self) {
@ -448,22 +464,28 @@ impl IOCompositor {
// Drain compositor port, sometimes messages contain channels that are blocking // Drain compositor port, sometimes messages contain channels that are blocking
// another thread from finishing (i.e. SetFrameTree). // another thread from finishing (i.e. SetFrameTree).
while self.port.try_recv_compositor_msg().is_some() {} while self
.global
.compositor_receiver
.try_recv_compositor_msg()
.is_some()
{}
// Tell the profiler, memory profiler, and scrolling timer to shut down. // Tell the profiler, memory profiler, and scrolling timer to shut down.
if let Ok((sender, receiver)) = ipc::channel() { if let Ok((sender, receiver)) = ipc::channel() {
self.time_profiler_chan self.global
.time_profiler_chan
.send(profile_time::ProfilerMsg::Exit(sender)); .send(profile_time::ProfilerMsg::Exit(sender));
let _ = receiver.recv(); let _ = receiver.recv();
} }
self.shutdown_state = ShutdownState::FinishedShuttingDown; self.global.shutdown_state = ShutdownState::FinishedShuttingDown;
} }
fn handle_browser_message(&mut self, msg: CompositorMsg) { fn handle_browser_message(&mut self, msg: CompositorMsg) {
trace_msg_from_constellation!(msg, "{msg:?}"); trace_msg_from_constellation!(msg, "{msg:?}");
match self.shutdown_state { match self.global.shutdown_state {
ShutdownState::NotShuttingDown => {}, ShutdownState::NotShuttingDown => {},
ShutdownState::ShuttingDown => { ShutdownState::ShuttingDown => {
self.handle_browser_message_while_shutting_down(msg); self.handle_browser_message_while_shutting_down(msg);
@ -550,7 +572,7 @@ impl IOCompositor {
CompositorMsg::LoadComplete(_) => { CompositorMsg::LoadComplete(_) => {
// If we're painting in headless mode, schedule a recomposite. // If we're painting in headless mode, schedule a recomposite.
if matches!(self.composite_target, CompositeTarget::PngFile(_)) || if matches!(self.composite_target, CompositeTarget::PngFile(_)) ||
self.exit_after_load self.global.exit_after_load
{ {
self.set_needs_repaint(RepaintReason::ReadyForScreenshot); self.set_needs_repaint(RepaintReason::ReadyForScreenshot);
} }
@ -597,7 +619,8 @@ impl IOCompositor {
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default())); txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default()));
self.generate_frame(&mut txn, RenderReasons::SCENE); self.generate_frame(&mut txn, RenderReasons::SCENE);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
}, },
@ -633,7 +656,8 @@ impl IOCompositor {
}], }],
); );
self.generate_frame(&mut txn, RenderReasons::APZ); self.generate_frame(&mut txn, RenderReasons::APZ);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
}, },
@ -693,7 +717,8 @@ impl IOCompositor {
.set_display_list(display_list_info.epoch, (pipeline_id, built_display_list)); .set_display_list(display_list_info.epoch, (pipeline_id, built_display_list));
self.update_transaction_with_all_scroll_offsets(&mut transaction); self.update_transaction_with_all_scroll_offsets(&mut transaction);
self.generate_frame(&mut transaction, RenderReasons::SCENE); self.generate_frame(&mut transaction, RenderReasons::SCENE);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
}, },
@ -708,14 +733,14 @@ impl IOCompositor {
// would be to listen to the TransactionNotifier for previous per-pipeline // would be to listen to the TransactionNotifier for previous per-pipeline
// transactions, but that isn't easily compatible with the event loop wakeup // transactions, but that isn't easily compatible with the event loop wakeup
// mechanism from libserver. // mechanism from libserver.
self.webrender_api.flush_scene_builder(); self.global.webrender_api.flush_scene_builder();
let result = self.hit_test_at_point_with_flags_and_pipeline(point, flags, pipeline); let result = self.hit_test_at_point_with_flags_and_pipeline(point, flags, pipeline);
let _ = sender.send(result); let _ = sender.send(result);
}, },
CrossProcessCompositorMessage::GenerateImageKey(sender) => { CrossProcessCompositorMessage::GenerateImageKey(sender) => {
let _ = sender.send(self.webrender_api.generate_image_key()); let _ = sender.send(self.global.webrender_api.generate_image_key());
}, },
CrossProcessCompositorMessage::UpdateImages(updates) => { CrossProcessCompositorMessage::UpdateImages(updates) => {
@ -731,7 +756,8 @@ impl IOCompositor {
}, },
} }
} }
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
}, },
@ -742,7 +768,8 @@ impl IOCompositor {
CrossProcessCompositorMessage::AddSystemFont(font_key, native_handle) => { CrossProcessCompositorMessage::AddSystemFont(font_key, native_handle) => {
let mut transaction = Transaction::new(); let mut transaction = Transaction::new();
transaction.add_native_font(font_key, native_handle); transaction.add_native_font(font_key, native_handle);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
}, },
@ -765,14 +792,16 @@ impl IOCompositor {
transaction.delete_font(key); transaction.delete_font(key);
} }
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
}, },
CrossProcessCompositorMessage::AddImage(key, desc, data) => { CrossProcessCompositorMessage::AddImage(key, desc, data) => {
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.add_image(key, desc, data.into(), None); txn.add_image(key, desc, data.into(), None);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
}, },
@ -782,10 +811,10 @@ impl IOCompositor {
result_sender, result_sender,
) => { ) => {
let font_keys = (0..number_of_font_keys) let font_keys = (0..number_of_font_keys)
.map(|_| self.webrender_api.generate_font_key()) .map(|_| self.global.webrender_api.generate_font_key())
.collect(); .collect();
let font_instance_keys = (0..number_of_font_instance_keys) let font_instance_keys = (0..number_of_font_instance_keys)
.map(|_| self.webrender_api.generate_font_instance_key()) .map(|_| self.global.webrender_api.generate_font_instance_key())
.collect(); .collect();
let _ = result_sender.send((font_keys, font_instance_keys)); let _ = result_sender.send((font_keys, font_instance_keys));
}, },
@ -832,7 +861,7 @@ impl IOCompositor {
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateImageKey( CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateImageKey(
sender, sender,
)) => { )) => {
let _ = sender.send(self.webrender_api.generate_image_key()); let _ = sender.send(self.global.webrender_api.generate_image_key());
}, },
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateFontKeys( CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateFontKeys(
number_of_font_keys, number_of_font_keys,
@ -840,10 +869,10 @@ impl IOCompositor {
result_sender, result_sender,
)) => { )) => {
let font_keys = (0..number_of_font_keys) let font_keys = (0..number_of_font_keys)
.map(|_| self.webrender_api.generate_font_key()) .map(|_| self.global.webrender_api.generate_font_key())
.collect(); .collect();
let font_instance_keys = (0..number_of_font_instance_keys) let font_instance_keys = (0..number_of_font_instance_keys)
.map(|_| self.webrender_api.generate_font_instance_key()) .map(|_| self.global.webrender_api.generate_font_instance_key())
.collect(); .collect();
let _ = result_sender.send((font_keys, font_instance_keys)); let _ = result_sender.send((font_keys, font_instance_keys));
}, },
@ -947,7 +976,8 @@ impl IOCompositor {
let mut transaction = Transaction::new(); let mut transaction = Transaction::new();
self.send_root_pipeline_display_list_in_transaction(&mut transaction); self.send_root_pipeline_display_list_in_transaction(&mut transaction);
self.generate_frame(&mut transaction, RenderReasons::SCENE); self.generate_frame(&mut transaction, RenderReasons::SCENE);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
} }
@ -986,7 +1016,7 @@ impl IOCompositor {
let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect); 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]); let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
for (_, webview) in self.webviews.painting_order() { for (_, webview) in self.global.webviews.painting_order() {
if let Some(pipeline_id) = webview.pipeline_id { if let Some(pipeline_id) = webview.pipeline_id {
let scaled_webview_rect = webview.rect / zoom_factor; let scaled_webview_rect = webview.rect / zoom_factor;
builder.push_iframe( builder.push_iframe(
@ -1042,7 +1072,7 @@ impl IOCompositor {
debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id); debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
let top_level_browsing_context_id = frame_tree.pipeline.top_level_browsing_context_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) { if let Some(webview) = self.global.webviews.get_mut(top_level_browsing_context_id) {
let new_pipeline_id = Some(frame_tree.pipeline.id); let new_pipeline_id = Some(frame_tree.pipeline.id);
if new_pipeline_id != webview.pipeline_id { if new_pipeline_id != webview.pipeline_id {
debug!( debug!(
@ -1058,7 +1088,7 @@ impl IOCompositor {
"{:?}: Creating new webview with pipeline {:?}", "{:?}: Creating new webview with pipeline {:?}",
top_level_browsing_context_id, pipeline_id top_level_browsing_context_id, pipeline_id
); );
if let Err(WebViewAlreadyExists(webview_id)) = self.webviews.add( if let Err(WebViewAlreadyExists(webview_id)) = self.global.webviews.add(
top_level_browsing_context_id, top_level_browsing_context_id,
WebView { WebView {
pipeline_id, pipeline_id,
@ -1069,7 +1099,7 @@ impl IOCompositor {
return; return;
} }
let msg = ConstellationMsg::WebViewOpened(top_level_browsing_context_id); let msg = ConstellationMsg::WebViewOpened(top_level_browsing_context_id);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e); warn!("Sending event to constellation failed ({:?}).", e);
} }
} }
@ -1083,7 +1113,7 @@ impl IOCompositor {
fn remove_webview(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) { fn remove_webview(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) {
debug!("{}: Removing", top_level_browsing_context_id); debug!("{}: Removing", top_level_browsing_context_id);
let Ok(webview) = self.webviews.remove(top_level_browsing_context_id) else { let Ok(webview) = self.global.webviews.remove(top_level_browsing_context_id) else {
warn!("{top_level_browsing_context_id}: Removing unknown webview"); warn!("{top_level_browsing_context_id}: Removing unknown webview");
return; return;
}; };
@ -1100,7 +1130,7 @@ impl IOCompositor {
debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}"); debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}");
let rect_changed; let rect_changed;
let size_changed; let size_changed;
match self.webviews.get_mut(webview_id) { match self.global.webviews.get_mut(webview_id) {
Some(webview) => { Some(webview) => {
rect_changed = rect != webview.rect; rect_changed = rect != webview.rect;
size_changed = rect.size() != webview.rect.size(); size_changed = rect.size() != webview.rect.size();
@ -1129,15 +1159,16 @@ impl IOCompositor {
debug!("{webview_id}: Showing webview; hide_others={hide_others}"); debug!("{webview_id}: Showing webview; hide_others={hide_others}");
let painting_order_changed = if hide_others { let painting_order_changed = if hide_others {
let result = self let result = self
.global
.webviews .webviews
.painting_order() .painting_order()
.map(|(&id, _)| id) .map(|(&id, _)| id)
.ne(once(webview_id)); .ne(once(webview_id));
self.webviews.hide_all(); self.global.webviews.hide_all();
self.webviews.show(webview_id)?; self.global.webviews.show(webview_id)?;
result result
} else { } else {
self.webviews.show(webview_id)? self.global.webviews.show(webview_id)?
}; };
if painting_order_changed { if painting_order_changed {
self.send_root_pipeline_display_list(); self.send_root_pipeline_display_list();
@ -1147,7 +1178,7 @@ impl IOCompositor {
pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> { pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
debug!("{webview_id}: Hiding webview"); debug!("{webview_id}: Hiding webview");
if self.webviews.hide(webview_id)? { if self.global.webviews.hide(webview_id)? {
self.send_root_pipeline_display_list(); self.send_root_pipeline_display_list();
} }
Ok(()) Ok(())
@ -1161,15 +1192,16 @@ impl IOCompositor {
debug!("{webview_id}: Raising webview to top; hide_others={hide_others}"); debug!("{webview_id}: Raising webview to top; hide_others={hide_others}");
let painting_order_changed = if hide_others { let painting_order_changed = if hide_others {
let result = self let result = self
.global
.webviews .webviews
.painting_order() .painting_order()
.map(|(&id, _)| id) .map(|(&id, _)| id)
.ne(once(webview_id)); .ne(once(webview_id));
self.webviews.hide_all(); self.global.webviews.hide_all();
self.webviews.raise_to_top(webview_id)?; self.global.webviews.raise_to_top(webview_id)?;
result result
} else { } else {
self.webviews.raise_to_top(webview_id)? self.global.webviews.raise_to_top(webview_id)?
}; };
if painting_order_changed { if painting_order_changed {
self.send_root_pipeline_display_list(); self.send_root_pipeline_display_list();
@ -1194,7 +1226,7 @@ impl IOCompositor {
}, },
WindowSizeType::Resize, WindowSizeType::Resize,
); );
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending window resize to constellation failed ({:?}).", e); warn!("Sending window resize to constellation failed ({:?}).", e);
} }
} }
@ -1267,7 +1299,7 @@ impl IOCompositor {
} }
pub fn on_rendering_context_resized(&mut self) -> bool { pub fn on_rendering_context_resized(&mut self) -> bool {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return false; return false;
} }
@ -1279,7 +1311,8 @@ impl IOCompositor {
let size = self.embedder_coordinates.get_viewport(); let size = self.embedder_coordinates.get_viewport();
transaction.set_document_view(size); transaction.set_document_view(size);
self.rendering_context.resize(size.size().to_untyped()); self.rendering_context.resize(size.size().to_untyped());
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
} }
@ -1310,7 +1343,8 @@ impl IOCompositor {
self.update_cursor(&result); self.update_cursor(&result);
if let Err(error) = self if let Err(error) = self
.constellation_chan .global
.constellation_sender
.send(ConstellationMsg::ForwardInputEvent(event, Some(result))) .send(ConstellationMsg::ForwardInputEvent(event, Some(result)))
{ {
warn!("Sending event to constellation failed ({error:?})."); warn!("Sending event to constellation failed ({error:?}).");
@ -1318,7 +1352,7 @@ impl IOCompositor {
} }
pub fn on_input_event(&mut self, event: InputEvent) { pub fn on_input_event(&mut self, event: InputEvent) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return; return;
} }
@ -1377,9 +1411,12 @@ impl IOCompositor {
) -> Vec<CompositorHitTestResult> { ) -> Vec<CompositorHitTestResult> {
// DevicePoint and WorldPoint are the same for us. // DevicePoint and WorldPoint are the same for us.
let world_point = WorldPoint::from_untyped(point.to_untyped()); let world_point = WorldPoint::from_untyped(point.to_untyped());
let results = let results = self.global.webrender_api.hit_test(
self.webrender_api self.webrender_document,
.hit_test(self.webrender_document, pipeline_id, world_point, flags); pipeline_id,
world_point,
flags,
);
results results
.items .items
@ -1419,7 +1456,8 @@ impl IOCompositor {
let event = InputEvent::Touch(event); let event = InputEvent::Touch(event);
if let Err(e) = self if let Err(e) = self
.constellation_chan .global
.constellation_sender
.send(ConstellationMsg::ForwardInputEvent(event, Some(result))) .send(ConstellationMsg::ForwardInputEvent(event, Some(result)))
{ {
warn!("Sending event to constellation failed ({:?}).", e); warn!("Sending event to constellation failed ({:?}).", e);
@ -1427,7 +1465,7 @@ impl IOCompositor {
} }
pub fn on_touch_event(&mut self, event: TouchEvent) { pub fn on_touch_event(&mut self, event: TouchEvent) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return; return;
} }
@ -1567,7 +1605,7 @@ impl IOCompositor {
cursor: DeviceIntPoint, cursor: DeviceIntPoint,
event_type: TouchEventType, event_type: TouchEventType,
) { ) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return; return;
} }
@ -1670,7 +1708,8 @@ impl IOCompositor {
} }
self.generate_frame(&mut transaction, RenderReasons::APZ); self.generate_frame(&mut transaction, RenderReasons::APZ);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
} }
@ -1745,7 +1784,7 @@ impl IOCompositor {
} }
} }
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
let webxr_running = self.webxr_main_thread.running(); let webxr_running = self.global.webxr_main_thread.running();
#[cfg(not(feature = "webxr"))] #[cfg(not(feature = "webxr"))]
let webxr_running = false; let webxr_running = false;
let animation_state = if pipeline_ids.is_empty() && !webxr_running { let animation_state = if pipeline_ids.is_empty() && !webxr_running {
@ -1777,7 +1816,7 @@ impl IOCompositor {
} }
let msg = ConstellationMsg::TickAnimation(pipeline_id, tick_type); let msg = ConstellationMsg::TickAnimation(pipeline_id, tick_type);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending tick to constellation failed ({:?}).", e); warn!("Sending tick to constellation failed ({:?}).", e);
} }
} }
@ -1800,7 +1839,7 @@ impl IOCompositor {
} }
pub fn on_zoom_reset_window_event(&mut self) { pub fn on_zoom_reset_window_event(&mut self) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return; return;
} }
@ -1809,7 +1848,7 @@ impl IOCompositor {
} }
pub fn on_zoom_window_event(&mut self, magnification: f32) { pub fn on_zoom_window_event(&mut self, magnification: f32) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return; return;
} }
@ -1819,7 +1858,7 @@ impl IOCompositor {
} }
fn update_after_zoom_or_hidpi_change(&mut self) { fn update_after_zoom_or_hidpi_change(&mut self) {
for (top_level_browsing_context_id, webview) in self.webviews.painting_order() { for (top_level_browsing_context_id, webview) in self.global.webviews.painting_order() {
self.send_window_size_message_for_top_level_browser_context( self.send_window_size_message_for_top_level_browser_context(
webview.rect, webview.rect,
*top_level_browsing_context_id, *top_level_browsing_context_id,
@ -1832,7 +1871,7 @@ impl IOCompositor {
/// Simulate a pinch zoom /// Simulate a pinch zoom
pub fn on_pinch_zoom_window_event(&mut self, magnification: f32) { pub fn on_pinch_zoom_window_event(&mut self, magnification: f32) {
if self.shutdown_state != ShutdownState::NotShuttingDown { if self.global.shutdown_state != ShutdownState::NotShuttingDown {
return; return;
} }
@ -1923,7 +1962,7 @@ impl IOCompositor {
// Pass the pipeline/epoch states to the constellation and check // Pass the pipeline/epoch states to the constellation and check
// if it's safe to output the image. // if it's safe to output the image.
let msg = ConstellationMsg::IsReadyToSaveImage(pipeline_epochs); let msg = ConstellationMsg::IsReadyToSaveImage(pipeline_epochs);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.global.constellation_sender.send(msg) {
warn!("Sending ready to save to constellation failed ({:?}).", e); warn!("Sending ready to save to constellation failed ({:?}).", e);
} }
self.ready_to_save_state = ReadyState::WaitingForConstellationReply; self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
@ -1959,7 +1998,9 @@ impl IOCompositor {
// Queue up any subsequent paints for animations. // Queue up any subsequent paints for animations.
self.process_animations(true); self.process_animations(true);
if matches!(self.composite_target, CompositeTarget::PngFile(_)) || self.exit_after_load { if matches!(self.composite_target, CompositeTarget::PngFile(_)) ||
self.global.exit_after_load
{
println!("Shutting down the Constellation after generating an output file or exit flag specified"); println!("Shutting down the Constellation after generating an output file or exit flag specified");
self.start_shutting_down(); self.start_shutting_down();
} }
@ -1991,7 +2032,7 @@ impl IOCompositor {
let wait_for_stable_image = matches!( let wait_for_stable_image = matches!(
target, target,
CompositeTarget::SharedMemory | CompositeTarget::PngFile(_) CompositeTarget::SharedMemory | CompositeTarget::PngFile(_)
) || self.exit_after_load; ) || self.global.exit_after_load;
if wait_for_stable_image { if wait_for_stable_image {
// The current image may be ready to output. However, if there are animations active, // The current image may be ready to output. However, if there are animations active,
@ -2013,7 +2054,7 @@ impl IOCompositor {
time_profile!( time_profile!(
ProfilerCategory::Compositing, ProfilerCategory::Compositing,
None, None,
self.time_profiler_chan.clone(), self.global.time_profiler_chan.clone(),
|| { || {
trace!("Compositing"); trace!("Compositing");
@ -2066,7 +2107,7 @@ impl IOCompositor {
time_profile!( time_profile!(
ProfilerCategory::ImageSaving, ProfilerCategory::ImageSaving,
None, None,
self.time_profiler_chan.clone(), self.global.time_profiler_chan.clone(),
|| match File::create(&*path) { || match File::create(&*path) {
Ok(mut file) => { Ok(mut file) => {
if let Some(image) = self.rendering_context.read_to_image(Rect::new( if let Some(image) = self.rendering_context.read_to_image(Rect::new(
@ -2157,7 +2198,7 @@ impl IOCompositor {
} }
fn clear_background(&self) { fn clear_background(&self) {
let gl = &self.webrender_gl; let gl = &self.global.webrender_gl;
self.assert_gl_framebuffer_complete(); self.assert_gl_framebuffer_complete();
// Always clear the entire RenderingContext, regardless of how many WebViews there are // Always clear the entire RenderingContext, regardless of how many WebViews there are
@ -2175,15 +2216,16 @@ impl IOCompositor {
#[track_caller] #[track_caller]
fn assert_no_gl_error(&self) { fn assert_no_gl_error(&self) {
debug_assert_eq!(self.webrender_gl.get_error(), gleam::gl::NO_ERROR); debug_assert_eq!(self.global.webrender_gl.get_error(), gleam::gl::NO_ERROR);
} }
#[track_caller] #[track_caller]
fn assert_gl_framebuffer_complete(&self) { fn assert_gl_framebuffer_complete(&self) {
debug_assert_eq!( debug_assert_eq!(
( (
self.webrender_gl.get_error(), self.global.webrender_gl.get_error(),
self.webrender_gl self.global
.webrender_gl
.check_frame_buffer_status(gleam::gl::FRAMEBUFFER) .check_frame_buffer_status(gleam::gl::FRAMEBUFFER)
), ),
(gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE) (gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE)
@ -2198,7 +2240,7 @@ impl IOCompositor {
// Check for new messages coming from the other threads in the system. // Check for new messages coming from the other threads in the system.
let mut compositor_messages = vec![]; let mut compositor_messages = vec![];
let mut found_recomposite_msg = false; let mut found_recomposite_msg = false;
while let Some(msg) = self.port.try_recv_compositor_msg() { while let Some(msg) = self.global.compositor_receiver.try_recv_compositor_msg() {
match msg { match msg {
CompositorMsg::NewWebRenderFrameReady(..) if found_recomposite_msg => { CompositorMsg::NewWebRenderFrameReady(..) if found_recomposite_msg => {
// Only take one of duplicate NewWebRendeFrameReady messages, but do subtract // Only take one of duplicate NewWebRendeFrameReady messages, but do subtract
@ -2215,7 +2257,7 @@ impl IOCompositor {
for msg in compositor_messages { for msg in compositor_messages {
self.handle_browser_message(msg); self.handle_browser_message(msg);
if self.shutdown_state == ShutdownState::FinishedShuttingDown { if self.global.shutdown_state == ShutdownState::FinishedShuttingDown {
return; return;
} }
} }
@ -2226,7 +2268,7 @@ impl IOCompositor {
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)] )]
pub fn perform_updates(&mut self) -> bool { pub fn perform_updates(&mut self) -> bool {
if self.shutdown_state == ShutdownState::FinishedShuttingDown { if self.global.shutdown_state == ShutdownState::FinishedShuttingDown {
return false; return false;
} }
@ -2241,7 +2283,7 @@ impl IOCompositor {
#[cfg(feature = "webxr")] #[cfg(feature = "webxr")]
// Run the WebXR main thread // Run the WebXR main thread
self.webxr_main_thread.run_one_frame(); self.global.webxr_main_thread.run_one_frame();
// The WebXR thread may make a different context current // The WebXR thread may make a different context current
if let Err(err) = self.rendering_context.make_current() { if let Err(err) = self.rendering_context.make_current() {
@ -2250,7 +2292,7 @@ impl IOCompositor {
if !self.pending_scroll_zoom_events.is_empty() { if !self.pending_scroll_zoom_events.is_empty() {
self.process_pending_scroll_events() self.process_pending_scroll_events()
} }
self.shutdown_state != ShutdownState::FinishedShuttingDown self.global.shutdown_state != ShutdownState::FinishedShuttingDown
} }
pub fn pinch_zoom_level(&self) -> Scale<f32, DevicePixel, DevicePixel> { pub fn pinch_zoom_level(&self) -> Scale<f32, DevicePixel, DevicePixel> {
@ -2288,7 +2330,8 @@ impl IOCompositor {
let mut txn = Transaction::new(); let mut txn = Transaction::new();
self.generate_frame(&mut txn, RenderReasons::TESTING); self.generate_frame(&mut txn, RenderReasons::TESTING);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
} }
@ -2313,12 +2356,13 @@ impl IOCompositor {
}; };
println!("Saving WebRender capture to {capture_path:?}"); println!("Saving WebRender capture to {capture_path:?}");
self.webrender_api self.global
.webrender_api
.save_capture(capture_path.clone(), CaptureBits::all()); .save_capture(capture_path.clone(), CaptureBits::all());
let version_file_path = capture_path.join("servo-version.txt"); let version_file_path = capture_path.join("servo-version.txt");
if let Err(error) = File::create(version_file_path) if let Err(error) = File::create(version_file_path)
.and_then(|mut file| write!(file, "{}", self.version_string)) .and_then(|mut file| write!(file, "{}", self.global.version_string))
{ {
eprintln!("Unable to write servo version for WebRender Capture: {error:?}"); eprintln!("Unable to write servo version for WebRender Capture: {error:?}");
} }
@ -2346,14 +2390,16 @@ impl IOCompositor {
Vec::new(), Vec::new(),
); );
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
} }
fn add_font(&mut self, font_key: FontKey, index: u32, data: Arc<IpcSharedMemory>) { fn add_font(&mut self, font_key: FontKey, index: u32, data: Arc<IpcSharedMemory>) {
let mut transaction = Transaction::new(); let mut transaction = Transaction::new();
transaction.add_raw_font(font_key, (**data).into(), index); transaction.add_raw_font(font_key, (**data).into(), index);
self.webrender_api self.global
.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
} }
} }

View file

@ -629,14 +629,14 @@ impl Servo {
/// The return value of this method indicates whether or not Servo, false indicates that Servo /// The return value of this method indicates whether or not Servo, false indicates that Servo
/// has finished shutting down and you should not spin the event loop any longer. /// has finished shutting down and you should not spin the event loop any longer.
pub fn spin_event_loop(&self) -> bool { pub fn spin_event_loop(&self) -> bool {
if self.compositor.borrow().shutdown_state == ShutdownState::FinishedShuttingDown { if self.compositor.borrow().shutdown_state() == ShutdownState::FinishedShuttingDown {
return false; return false;
} }
self.compositor.borrow_mut().receive_messages(); self.compositor.borrow_mut().receive_messages();
// Only handle incoming embedder messages if the compositor hasn't already started shutting down. // Only handle incoming embedder messages if the compositor hasn't already started shutting down.
if self.compositor.borrow().shutdown_state == ShutdownState::NotShuttingDown { if self.compositor.borrow().shutdown_state() == ShutdownState::NotShuttingDown {
while let Ok(message) = self.embedder_receiver.try_recv() { while let Ok(message) = self.embedder_receiver.try_recv() {
self.handle_embedder_message(message) self.handle_embedder_message(message)
} }
@ -650,7 +650,7 @@ impl Servo {
self.compositor.borrow_mut().perform_updates(); self.compositor.borrow_mut().perform_updates();
self.send_new_frame_ready_messages(); self.send_new_frame_ready_messages();
if self.compositor.borrow().shutdown_state == ShutdownState::FinishedShuttingDown { if self.compositor.borrow().shutdown_state() == ShutdownState::FinishedShuttingDown {
return false; return false;
} }