compositor: Unify the cross process and in-process API (#36443)

Because there used to be two traits exposing messages to the compositor,
there were two kinds of messages that could be sent:

1. In-process messages from the `Constellation`
2. Cross-process messages from other parts of Servo

Now these two types of messages can be unified into one type. With that
done the compositor can simply keep a single `IpcReceiver` for all
messages, instead of having to set up a route for the cross-process
messsages. This decreases overhead of cross proceses messages a bit, but
more importantly solves an issue where Servo would rely on the
compositor's cross-process message route after the `Constellation` had
called `ROUTER.shutdown()`.

This is part of #36442.

Testing: This is covered by existing WPT tests.
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-12 23:38:22 +02:00 committed by GitHub
parent 5f0f457ac3
commit 4c55104b36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 95 additions and 215 deletions

View file

@ -19,8 +19,7 @@ use bitflags::bitflags;
use compositing_traits::display_list::{CompositorDisplayListInfo, HitTestInfo, ScrollTree}; use compositing_traits::display_list::{CompositorDisplayListInfo, HitTestInfo, ScrollTree};
use compositing_traits::rendering_context::RenderingContext; use compositing_traits::rendering_context::RenderingContext;
use compositing_traits::{ use compositing_traits::{
CompositionPipeline, CompositorMsg, CompositorReceiver, CrossProcessCompositorMessage, CompositionPipeline, CompositorMsg, ImageUpdate, RendererWebView, SendableFrameTree,
ImageUpdate, RendererWebView, SendableFrameTree,
}; };
use constellation_traits::{ use constellation_traits::{
AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent, WindowSizeType, AnimationTickType, EmbedderToConstellationMessage, PaintMetricEvent, WindowSizeType,
@ -33,7 +32,7 @@ use embedder_traits::{
}; };
use euclid::{Box2D, Point2D, Rect, Scale, Size2D, Transform3D}; use euclid::{Box2D, Point2D, Rect, Scale, Size2D, Transform3D};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use ipc_channel::ipc::{self, IpcSharedMemory}; use ipc_channel::ipc::{self, IpcReceiver, IpcSharedMemory};
use libc::c_void; use libc::c_void;
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use pixels::{CorsStatus, Image, ImageFrame, PixelFormat}; use pixels::{CorsStatus, Image, ImageFrame, PixelFormat};
@ -96,7 +95,7 @@ pub struct ServoRenderer {
shutdown_state: Rc<Cell<ShutdownState>>, shutdown_state: Rc<Cell<ShutdownState>>,
/// The port on which we receive messages. /// The port on which we receive messages.
compositor_receiver: CompositorReceiver, compositor_receiver: IpcReceiver<CompositorMsg>,
/// The channel on which messages can be sent to the constellation. /// The channel on which messages can be sent to the constellation.
pub(crate) constellation_sender: Sender<EmbedderToConstellationMessage>, pub(crate) constellation_sender: Sender<EmbedderToConstellationMessage>,
@ -515,8 +514,8 @@ impl IOCompositor {
.global .global
.borrow_mut() .borrow_mut()
.compositor_receiver .compositor_receiver
.try_recv_compositor_msg() .try_recv()
.is_some() .is_ok()
{} {}
// Tell the profiler, memory profiler, and scrolling timer to shut down. // Tell the profiler, memory profiler, and scrolling timer to shut down.
@ -678,33 +677,14 @@ impl IOCompositor {
webview.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); webview.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point }));
}, },
CompositorMsg::CrossProcess(cross_proces_message) => { CompositorMsg::SendInitialTransaction(pipeline) => {
self.handle_cross_process_message(cross_proces_message);
},
}
}
/// Accept messages from content processes that need to be relayed to the WebRender
/// instance in the parent process.
#[cfg_attr(
feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)]
fn handle_cross_process_message(&mut self, msg: CrossProcessCompositorMessage) {
match msg {
CrossProcessCompositorMessage::SendInitialTransaction(pipeline) => {
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.global.borrow_mut().send_transaction(txn); self.global.borrow_mut().send_transaction(txn);
}, },
CrossProcessCompositorMessage::SendScrollNode( CompositorMsg::SendScrollNode(webview_id, pipeline_id, point, external_scroll_id) => {
webview_id,
pipeline_id,
point,
external_scroll_id,
) => {
let Some(webview) = self.webviews.get_mut(webview_id) else { let Some(webview) = self.webviews.get_mut(webview_id) else {
return; return;
}; };
@ -738,7 +718,7 @@ impl IOCompositor {
self.global.borrow_mut().send_transaction(txn); self.global.borrow_mut().send_transaction(txn);
}, },
CrossProcessCompositorMessage::SendDisplayList { CompositorMsg::SendDisplayList {
webview_id, webview_id,
display_list_descriptor, display_list_descriptor,
display_list_receiver, display_list_receiver,
@ -827,7 +807,7 @@ impl IOCompositor {
self.global.borrow_mut().send_transaction(transaction); self.global.borrow_mut().send_transaction(transaction);
}, },
CrossProcessCompositorMessage::HitTest(pipeline, point, flags, sender) => { CompositorMsg::HitTest(pipeline, point, flags, sender) => {
// When a display list is sent to WebRender, it starts scene building in a // When a display list is sent to WebRender, it starts scene building in a
// separate thread and then that display list is available for hit testing. // separate thread and then that display list is available for hit testing.
// Without flushing scene building, any hit test we do might be done against // Without flushing scene building, any hit test we do might be done against
@ -853,11 +833,11 @@ impl IOCompositor {
let _ = sender.send(result); let _ = sender.send(result);
}, },
CrossProcessCompositorMessage::GenerateImageKey(sender) => { CompositorMsg::GenerateImageKey(sender) => {
let _ = sender.send(self.global.borrow().webrender_api.generate_image_key()); let _ = sender.send(self.global.borrow().webrender_api.generate_image_key());
}, },
CrossProcessCompositorMessage::UpdateImages(updates) => { CompositorMsg::UpdateImages(updates) => {
let mut txn = Transaction::new(); let mut txn = Transaction::new();
for update in updates { for update in updates {
match update { match update {
@ -873,26 +853,21 @@ impl IOCompositor {
self.global.borrow_mut().send_transaction(txn); self.global.borrow_mut().send_transaction(txn);
}, },
CrossProcessCompositorMessage::AddFont(font_key, data, index) => { CompositorMsg::AddFont(font_key, data, index) => {
self.add_font(font_key, index, data); self.add_font(font_key, index, data);
}, },
CrossProcessCompositorMessage::AddSystemFont(font_key, native_handle) => { CompositorMsg::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.global.borrow_mut().send_transaction(transaction); self.global.borrow_mut().send_transaction(transaction);
}, },
CrossProcessCompositorMessage::AddFontInstance( CompositorMsg::AddFontInstance(font_instance_key, font_key, size, flags) => {
font_instance_key,
font_key,
size,
flags,
) => {
self.add_font_instance(font_instance_key, font_key, size, flags); self.add_font_instance(font_instance_key, font_key, size, flags);
}, },
CrossProcessCompositorMessage::RemoveFonts(keys, instance_keys) => { CompositorMsg::RemoveFonts(keys, instance_keys) => {
let mut transaction = Transaction::new(); let mut transaction = Transaction::new();
for instance in instance_keys.into_iter() { for instance in instance_keys.into_iter() {
@ -905,13 +880,13 @@ impl IOCompositor {
self.global.borrow_mut().send_transaction(transaction); self.global.borrow_mut().send_transaction(transaction);
}, },
CrossProcessCompositorMessage::AddImage(key, desc, data) => { CompositorMsg::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.global.borrow_mut().send_transaction(txn); self.global.borrow_mut().send_transaction(txn);
}, },
CrossProcessCompositorMessage::GenerateFontKeys( CompositorMsg::GenerateFontKeys(
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
result_sender, result_sender,
@ -929,7 +904,7 @@ impl IOCompositor {
.collect(); .collect();
let _ = result_sender.send((font_keys, font_instance_keys)); let _ = result_sender.send((font_keys, font_instance_keys));
}, },
CrossProcessCompositorMessage::GetClientWindowRect(webview_id, response_sender) => { CompositorMsg::GetClientWindowRect(webview_id, response_sender) => {
let screen_geometry = self.webview_screen_geometry(webview_id); let screen_geometry = self.webview_screen_geometry(webview_id);
let rect = DeviceIntRect::from_origin_and_size( let rect = DeviceIntRect::from_origin_and_size(
screen_geometry.offset, screen_geometry.offset,
@ -942,7 +917,7 @@ impl IOCompositor {
warn!("Sending response to get client window failed ({error:?})."); warn!("Sending response to get client window failed ({error:?}).");
} }
}, },
CrossProcessCompositorMessage::GetScreenSize(webview_id, response_sender) => { CompositorMsg::GetScreenSize(webview_id, response_sender) => {
let screen_geometry = self.webview_screen_geometry(webview_id); let screen_geometry = self.webview_screen_geometry(webview_id);
let screen_size = screen_geometry.size.to_f32() / self.hidpi_factor; let screen_size = screen_geometry.size.to_f32() / self.hidpi_factor;
@ -950,7 +925,7 @@ impl IOCompositor {
warn!("Sending response to get screen size failed ({error:?})."); warn!("Sending response to get screen size failed ({error:?}).");
} }
}, },
CrossProcessCompositorMessage::GetAvailableScreenSize(webview_id, response_sender) => { CompositorMsg::GetAvailableScreenSize(webview_id, response_sender) => {
let screen_geometry = self.webview_screen_geometry(webview_id); let screen_geometry = self.webview_screen_geometry(webview_id);
let available_screen_size = let available_screen_size =
screen_geometry.available_size.to_f32() / self.hidpi_factor; screen_geometry.available_size.to_f32() / self.hidpi_factor;
@ -990,16 +965,14 @@ impl IOCompositor {
} }
let _ = sender.send(()); let _ = sender.send(());
}, },
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateImageKey( CompositorMsg::GenerateImageKey(sender) => {
sender,
)) => {
let _ = sender.send(self.global.borrow().webrender_api.generate_image_key()); let _ = sender.send(self.global.borrow().webrender_api.generate_image_key());
}, },
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateFontKeys( CompositorMsg::GenerateFontKeys(
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
result_sender, result_sender,
)) => { ) => {
let font_keys = (0..number_of_font_keys) let font_keys = (0..number_of_font_keys)
.map(|_| self.global.borrow().webrender_api.generate_font_key()) .map(|_| self.global.borrow().webrender_api.generate_font_key())
.collect(); .collect();
@ -1013,26 +986,17 @@ impl IOCompositor {
.collect(); .collect();
let _ = result_sender.send((font_keys, font_instance_keys)); let _ = result_sender.send((font_keys, font_instance_keys));
}, },
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetClientWindowRect( CompositorMsg::GetClientWindowRect(_, response_sender) => {
_,
response_sender,
)) => {
if let Err(error) = response_sender.send(Default::default()) { if let Err(error) = response_sender.send(Default::default()) {
warn!("Sending response to get client window failed ({error:?})."); warn!("Sending response to get client window failed ({error:?}).");
} }
}, },
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetScreenSize( CompositorMsg::GetScreenSize(_, response_sender) => {
_,
response_sender,
)) => {
if let Err(error) = response_sender.send(Default::default()) { if let Err(error) = response_sender.send(Default::default()) {
warn!("Sending response to get client window failed ({error:?})."); warn!("Sending response to get client window failed ({error:?}).");
} }
}, },
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetAvailableScreenSize( CompositorMsg::GetAvailableScreenSize(_, response_sender) => {
_,
response_sender,
)) => {
if let Err(error) = response_sender.send(Default::default()) { if let Err(error) = response_sender.send(Default::default()) {
warn!("Sending response to get client window failed ({error:?})."); warn!("Sending response to get client window failed ({error:?}).");
} }
@ -1672,12 +1636,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 while let Ok(msg) = self.global.borrow_mut().compositor_receiver.try_recv() {
.global
.borrow_mut()
.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

View file

@ -8,10 +8,11 @@ use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use compositing_traits::rendering_context::RenderingContext; use compositing_traits::rendering_context::RenderingContext;
use compositing_traits::{CompositorProxy, CompositorReceiver}; use compositing_traits::{CompositorMsg, CompositorProxy};
use constellation_traits::EmbedderToConstellationMessage; use constellation_traits::EmbedderToConstellationMessage;
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use embedder_traits::ShutdownState; use embedder_traits::ShutdownState;
use ipc_channel::ipc::IpcReceiver;
use profile_traits::{mem, time}; use profile_traits::{mem, time};
use webrender::RenderApi; use webrender::RenderApi;
use webrender_api::DocumentId; use webrender_api::DocumentId;
@ -32,7 +33,7 @@ pub struct InitialCompositorState {
/// A channel to the compositor. /// A channel to the compositor.
pub sender: CompositorProxy, pub sender: CompositorProxy,
/// A port on which messages inbound to the compositor can be received. /// A port on which messages inbound to the compositor can be received.
pub receiver: CompositorReceiver, pub receiver: IpcReceiver<CompositorMsg>,
/// A channel to the constellation. /// A channel to the constellation.
pub constellation_chan: Sender<EmbedderToConstellationMessage>, pub constellation_chan: Sender<EmbedderToConstellationMessage>,
/// A channel to the time profiler thread. /// A channel to the time profiler thread.

View file

@ -42,7 +42,21 @@ mod from_constellation {
Self::LoadComplete(..) => target!("LoadComplete"), Self::LoadComplete(..) => target!("LoadComplete"),
Self::WebDriverMouseButtonEvent(..) => target!("WebDriverMouseButtonEvent"), Self::WebDriverMouseButtonEvent(..) => target!("WebDriverMouseButtonEvent"),
Self::WebDriverMouseMoveEvent(..) => target!("WebDriverMouseMoveEvent"), Self::WebDriverMouseMoveEvent(..) => target!("WebDriverMouseMoveEvent"),
Self::CrossProcess(_) => target!("CrossProcess"), Self::SendInitialTransaction(..) => target!("SendInitialTransaction"),
Self::SendScrollNode(..) => target!("SendScrollNode"),
Self::SendDisplayList { .. } => todo!("SendDisplayList"),
Self::HitTest(..) => target!("HitTest"),
Self::GenerateImageKey(..) => target!("GenerateImageKey"),
Self::AddImage(..) => target!("AddImage"),
Self::UpdateImages(..) => target!("UpdateImages"),
Self::GenerateFontKeys(..) => target!("GenerateFontKeys"),
Self::AddFont(..) => target!("AddFont"),
Self::AddSystemFont(..) => target!("AddSystemFont"),
Self::AddFontInstance(..) => target!("AddFontInstance"),
Self::RemoveFonts(..) => target!("RemoveFonts"),
Self::GetClientWindowRect(..) => target!("GetClientWindowRect"),
Self::GetScreenSize(..) => target!("GetScreenSize"),
Self::GetAvailableScreenSize(..) => target!("GetAvailableScreenSize"),
} }
} }
} }

View file

@ -291,8 +291,7 @@ impl Pipeline {
webrender_document: state.webrender_document, webrender_document: state.webrender_document,
cross_process_compositor_api: state cross_process_compositor_api: state
.compositor_proxy .compositor_proxy
.cross_process_compositor_api .cross_process_compositor_api(),
.clone(),
webgl_chan: state.webgl_chan, webgl_chan: state.webgl_chan,
webxr_registry: state.webxr_registry, webxr_registry: state.webxr_registry,
player_context: state.player_context, player_context: state.player_context,

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use compositing_traits::CrossProcessCompositorMessage; use compositing_traits::CompositorMsg;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::Size2D; use euclid::Size2D;
use profile_traits::ipc; use profile_traits::ipc;
@ -41,7 +41,7 @@ impl Screen {
self.window self.window
.compositor_api() .compositor_api()
.sender() .sender()
.send(CrossProcessCompositorMessage::GetScreenSize( .send(CompositorMsg::GetScreenSize(
self.window.webview_id(), self.window.webview_id(),
sender, sender,
)) ))
@ -57,7 +57,7 @@ impl Screen {
self.window self.window
.compositor_api() .compositor_api()
.sender() .sender()
.send(CrossProcessCompositorMessage::GetAvailableScreenSize( .send(CompositorMsg::GetAvailableScreenSize(
self.window.webview_id(), self.window.webview_id(),
sender, sender,
)) ))

View file

@ -1898,10 +1898,7 @@ impl Window {
let (sender, receiver) = let (sender, receiver) =
ProfiledIpc::channel::<DeviceIndependentIntRect>(timer_profile_chan).unwrap(); ProfiledIpc::channel::<DeviceIndependentIntRect>(timer_profile_chan).unwrap();
let _ = self.compositor_api.sender().send( let _ = self.compositor_api.sender().send(
compositing_traits::CrossProcessCompositorMessage::GetClientWindowRect( compositing_traits::CompositorMsg::GetClientWindowRect(self.webview_id(), sender),
self.webview_id(),
sender,
),
); );
let rect = receiver.recv().unwrap_or_default(); let rect = receiver.recv().unwrap_or_default();
( (

View file

@ -48,8 +48,8 @@ pub use compositing_traits::rendering_context::{
OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext, OffscreenRenderingContext, RenderingContext, SoftwareRenderingContext, WindowRenderingContext,
}; };
use compositing_traits::{ use compositing_traits::{
CompositorMsg, CompositorProxy, CompositorReceiver, CrossProcessCompositorApi, CompositorMsg, CompositorProxy, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry,
WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, WebrenderImageHandlerType, WebrenderImageHandlerType,
}; };
#[cfg(all( #[cfg(all(
not(target_os = "windows"), not(target_os = "windows"),
@ -82,7 +82,6 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
pub use gleam::gl; pub use gleam::gl;
use gleam::gl::RENDERER; use gleam::gl::RENDERER;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
pub use keyboard_types::*; pub use keyboard_types::*;
use log::{Log, Metadata, Record, debug, warn}; use log::{Log, Metadata, Record, debug, warn};
use media::{GlApi, NativeDisplay, WindowGLContext}; use media::{GlApi, NativeDisplay, WindowGLContext};
@ -302,8 +301,6 @@ impl Servo {
// messages to client may need to pump a platform-specific event loop // messages to client may need to pump a platform-specific event loop
// to deliver the message. // to deliver the message.
let event_loop_waker = embedder.create_event_loop_waker(); let event_loop_waker = embedder.create_event_loop_waker();
let (compositor_proxy, compositor_receiver) =
create_compositor_channel(event_loop_waker.clone());
let (embedder_proxy, embedder_receiver) = create_embedder_channel(event_loop_waker.clone()); let (embedder_proxy, embedder_receiver) = create_embedder_channel(event_loop_waker.clone());
let time_profiler_chan = profile_time::Profiler::create( let time_profiler_chan = profile_time::Profiler::create(
&opts.time_profiling, &opts.time_profiling,
@ -311,6 +308,12 @@ impl Servo {
); );
let mem_profiler_chan = profile_mem::Profiler::create(); let mem_profiler_chan = profile_mem::Profiler::create();
let (compositor_sender, compositor_receiver) = ipc::channel().expect("ipc channel failure");
let compositor_proxy = CompositorProxy {
sender: compositor_sender,
event_loop_waker: event_loop_waker.clone(),
};
let devtools_sender = if pref!(devtools_server_enabled) { let devtools_sender = if pref!(devtools_server_enabled) {
Some(devtools::start_server( Some(devtools::start_server(
pref!(devtools_server_port) as u16, pref!(devtools_server_port) as u16,
@ -1007,34 +1010,6 @@ fn create_embedder_channel(
) )
} }
fn create_compositor_channel(
event_loop_waker: Box<dyn EventLoopWaker>,
) -> (CompositorProxy, CompositorReceiver) {
let (sender, receiver) = unbounded();
let (compositor_ipc_sender, compositor_ipc_receiver) =
ipc::channel().expect("ipc channel failure");
let cross_process_compositor_api = CrossProcessCompositorApi(compositor_ipc_sender);
let compositor_proxy = CompositorProxy {
sender,
cross_process_compositor_api,
event_loop_waker,
};
let compositor_proxy_clone = compositor_proxy.clone();
ROUTER.add_typed_route(
compositor_ipc_receiver,
Box::new(move |message| {
compositor_proxy_clone.send(CompositorMsg::CrossProcess(
message.expect("Could not convert Compositor message"),
));
}),
);
(compositor_proxy, CompositorReceiver { receiver })
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn create_constellation( fn create_constellation(
config_dir: Option<PathBuf>, config_dir: Option<PathBuf>,
@ -1071,11 +1046,11 @@ fn create_constellation(
); );
let system_font_service = Arc::new( let system_font_service = Arc::new(
SystemFontService::spawn(compositor_proxy.cross_process_compositor_api.clone()).to_proxy(), SystemFontService::spawn(compositor_proxy.cross_process_compositor_api()).to_proxy(),
); );
let (canvas_create_sender, canvas_ipc_sender) = CanvasPaintThread::start( let (canvas_create_sender, canvas_ipc_sender) = CanvasPaintThread::start(
compositor_proxy.cross_process_compositor_api.clone(), compositor_proxy.cross_process_compositor_api(),
system_font_service.clone(), system_font_service.clone(),
public_resource_threads.clone(), public_resource_threads.clone(),
); );

View file

@ -7,7 +7,6 @@
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use base::id::{PipelineId, WebViewId}; use base::id::{PipelineId, WebViewId};
use crossbeam_channel::{Receiver, Sender};
use embedder_traits::{ use embedder_traits::{
AnimationState, EventLoopWaker, MouseButton, MouseButtonAction, TouchEventResult, AnimationState, EventLoopWaker, MouseButton, MouseButtonAction, TouchEventResult,
}; };
@ -22,7 +21,6 @@ use webrender_api::DocumentId;
pub mod display_list; pub mod display_list;
pub mod rendering_context; pub mod rendering_context;
use core::fmt;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -43,11 +41,7 @@ use webrender_api::{
/// Sends messages to the compositor. /// Sends messages to the compositor.
#[derive(Clone)] #[derive(Clone)]
pub struct CompositorProxy { pub struct CompositorProxy {
pub sender: Sender<CompositorMsg>, pub sender: IpcSender<CompositorMsg>,
/// Access to [`Self::sender`] that is possible to send across an IPC
/// channel. These messages are routed via the router thread to
/// [`Self::sender`].
pub cross_process_compositor_api: CrossProcessCompositorApi,
pub event_loop_waker: Box<dyn EventLoopWaker>, pub event_loop_waker: Box<dyn EventLoopWaker>,
} }
@ -58,24 +52,14 @@ impl CompositorProxy {
} }
self.event_loop_waker.wake(); self.event_loop_waker.wake();
} }
}
/// The port that the compositor receives messages on. pub fn cross_process_compositor_api(&self) -> CrossProcessCompositorApi {
pub struct CompositorReceiver { CrossProcessCompositorApi(self.sender.clone())
pub receiver: Receiver<CompositorMsg>,
}
impl CompositorReceiver {
pub fn try_recv_compositor_msg(&mut self) -> Option<CompositorMsg> {
self.receiver.try_recv().ok()
}
pub fn recv_compositor_msg(&mut self) -> CompositorMsg {
self.receiver.recv().unwrap()
} }
} }
/// Messages from (or via) the constellation thread to the compositor. /// Messages from (or via) the constellation thread to the compositor.
#[derive(IntoStaticStr)] #[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum CompositorMsg { pub enum CompositorMsg {
/// Alerts the compositor that the given pipeline has changed whether it is running animations. /// Alerts the compositor that the given pipeline has changed whether it is running animations.
ChangeRunningAnimationsState(WebViewId, PipelineId, AnimationState), ChangeRunningAnimationsState(WebViewId, PipelineId, AnimationState),
@ -108,32 +92,6 @@ pub enum CompositorMsg {
/// WebDriver mouse move event /// WebDriver mouse move event
WebDriverMouseMoveEvent(WebViewId, f32, f32), WebDriverMouseMoveEvent(WebViewId, f32, f32),
/// Messages forwarded to the compositor by the constellation from other crates. These
/// messages are mainly passed on from the compositor to WebRender.
CrossProcess(CrossProcessCompositorMessage),
}
pub struct SendableFrameTree {
pub pipeline: CompositionPipeline,
pub children: Vec<SendableFrameTree>,
}
/// The subset of the pipeline that is needed for layer composition.
#[derive(Clone)]
pub struct CompositionPipeline {
pub id: PipelineId,
pub webview_id: WebViewId,
}
impl Debug for CompositorMsg {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
let string: &'static str = self.into();
write!(formatter, "{string}")
}
}
#[derive(Deserialize, Serialize)]
pub enum CrossProcessCompositorMessage {
/// Inform WebRender of the existence of this pipeline. /// Inform WebRender of the existence of this pipeline.
SendInitialTransaction(WebRenderPipelineId), SendInitialTransaction(WebRenderPipelineId),
/// Perform a scroll operation. /// Perform a scroll operation.
@ -193,31 +151,29 @@ pub enum CrossProcessCompositorMessage {
GetAvailableScreenSize(WebViewId, IpcSender<DeviceIndependentIntSize>), GetAvailableScreenSize(WebViewId, IpcSender<DeviceIndependentIntSize>),
} }
impl fmt::Debug for CrossProcessCompositorMessage { impl Debug for CompositorMsg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
match self { let string: &'static str = self.into();
Self::AddImage(..) => f.write_str("AddImage"), write!(formatter, "{string}")
Self::GenerateFontKeys(..) => f.write_str("GenerateFontKeys"),
Self::AddSystemFont(..) => f.write_str("AddSystemFont"),
Self::SendInitialTransaction(..) => f.write_str("SendInitialTransaction"),
Self::SendScrollNode(..) => f.write_str("SendScrollNode"),
Self::SendDisplayList { .. } => f.write_str("SendDisplayList"),
Self::HitTest(..) => f.write_str("HitTest"),
Self::GenerateImageKey(..) => f.write_str("GenerateImageKey"),
Self::UpdateImages(..) => f.write_str("UpdateImages"),
Self::RemoveFonts(..) => f.write_str("RemoveFonts"),
Self::AddFontInstance(..) => f.write_str("AddFontInstance"),
Self::AddFont(..) => f.write_str("AddFont"),
Self::GetClientWindowRect(..) => f.write_str("GetClientWindowRect"),
Self::GetScreenSize(..) => f.write_str("GetScreenSize"),
Self::GetAvailableScreenSize(..) => f.write_str("GetAvailableScreenSize"),
}
} }
} }
#[derive(Deserialize, Serialize)]
pub struct SendableFrameTree {
pub pipeline: CompositionPipeline,
pub children: Vec<SendableFrameTree>,
}
/// The subset of the pipeline that is needed for layer composition.
#[derive(Clone, Deserialize, Serialize)]
pub struct CompositionPipeline {
pub id: PipelineId,
pub webview_id: WebViewId,
}
/// A mechanism to send messages from ScriptThread to the parent process' WebRender instance. /// A mechanism to send messages from ScriptThread to the parent process' WebRender instance.
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
pub struct CrossProcessCompositorApi(pub IpcSender<CrossProcessCompositorMessage>); pub struct CrossProcessCompositorApi(pub IpcSender<CompositorMsg>);
impl CrossProcessCompositorApi { impl CrossProcessCompositorApi {
/// Create a new [`CrossProcessCompositorApi`] struct that does not have a listener on the other /// Create a new [`CrossProcessCompositorApi`] struct that does not have a listener on the other
@ -228,18 +184,13 @@ impl CrossProcessCompositorApi {
} }
/// Get the sender for this proxy. /// Get the sender for this proxy.
pub fn sender(&self) -> &IpcSender<CrossProcessCompositorMessage> { pub fn sender(&self) -> &IpcSender<CompositorMsg> {
&self.0 &self.0
} }
/// Inform WebRender of the existence of this pipeline. /// Inform WebRender of the existence of this pipeline.
pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) { pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) {
if let Err(e) = self if let Err(e) = self.0.send(CompositorMsg::SendInitialTransaction(pipeline)) {
.0
.send(CrossProcessCompositorMessage::SendInitialTransaction(
pipeline,
))
{
warn!("Error sending initial transaction: {}", e); warn!("Error sending initial transaction: {}", e);
} }
} }
@ -252,7 +203,7 @@ impl CrossProcessCompositorApi {
point: LayoutPoint, point: LayoutPoint,
scroll_id: ExternalScrollId, scroll_id: ExternalScrollId,
) { ) {
if let Err(e) = self.0.send(CrossProcessCompositorMessage::SendScrollNode( if let Err(e) = self.0.send(CompositorMsg::SendScrollNode(
webview_id, webview_id,
pipeline_id, pipeline_id,
point, point,
@ -271,7 +222,7 @@ impl CrossProcessCompositorApi {
) { ) {
let (display_list_data, display_list_descriptor) = list.into_data(); let (display_list_data, display_list_descriptor) = list.into_data();
let (display_list_sender, display_list_receiver) = ipc::bytes_channel().unwrap(); let (display_list_sender, display_list_receiver) = ipc::bytes_channel().unwrap();
if let Err(e) = self.0.send(CrossProcessCompositorMessage::SendDisplayList { if let Err(e) = self.0.send(CompositorMsg::SendDisplayList {
webview_id, webview_id,
display_list_descriptor, display_list_descriptor,
display_list_receiver, display_list_receiver,
@ -306,9 +257,7 @@ impl CrossProcessCompositorApi {
) -> Vec<CompositorHitTestResult> { ) -> Vec<CompositorHitTestResult> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
self.0 self.0
.send(CrossProcessCompositorMessage::HitTest( .send(CompositorMsg::HitTest(pipeline, point, flags, sender))
pipeline, point, flags, sender,
))
.expect("error sending hit test"); .expect("error sending hit test");
receiver.recv().expect("error receiving hit test result") receiver.recv().expect("error receiving hit test result")
} }
@ -316,9 +265,7 @@ impl CrossProcessCompositorApi {
/// Create a new image key. Blocks until the key is available. /// Create a new image key. Blocks until the key is available.
pub fn generate_image_key(&self) -> Option<ImageKey> { pub fn generate_image_key(&self) -> Option<ImageKey> {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
self.0 self.0.send(CompositorMsg::GenerateImageKey(sender)).ok()?;
.send(CrossProcessCompositorMessage::GenerateImageKey(sender))
.ok()?;
receiver.recv().ok() receiver.recv().ok()
} }
@ -328,19 +275,14 @@ impl CrossProcessCompositorApi {
descriptor: ImageDescriptor, descriptor: ImageDescriptor,
data: SerializableImageData, data: SerializableImageData,
) { ) {
if let Err(e) = self.0.send(CrossProcessCompositorMessage::AddImage( if let Err(e) = self.0.send(CompositorMsg::AddImage(key, descriptor, data)) {
key, descriptor, data,
)) {
warn!("Error sending image update: {}", e); warn!("Error sending image update: {}", e);
} }
} }
/// Perform an image resource update operation. /// Perform an image resource update operation.
pub fn update_images(&self, updates: Vec<ImageUpdate>) { pub fn update_images(&self, updates: Vec<ImageUpdate>) {
if let Err(e) = self if let Err(e) = self.0.send(CompositorMsg::UpdateImages(updates)) {
.0
.send(CrossProcessCompositorMessage::UpdateImages(updates))
{
warn!("error sending image updates: {}", e); warn!("error sending image updates: {}", e);
} }
} }
@ -353,10 +295,7 @@ impl CrossProcessCompositorApi {
if keys.is_empty() && instance_keys.is_empty() { if keys.is_empty() && instance_keys.is_empty() {
return; return;
} }
let _ = self.0.send(CrossProcessCompositorMessage::RemoveFonts( let _ = self.0.send(CompositorMsg::RemoveFonts(keys, instance_keys));
keys,
instance_keys,
));
} }
pub fn add_font_instance( pub fn add_font_instance(
@ -366,7 +305,7 @@ impl CrossProcessCompositorApi {
size: f32, size: f32,
flags: FontInstanceFlags, flags: FontInstanceFlags,
) { ) {
let _x = self.0.send(CrossProcessCompositorMessage::AddFontInstance( let _x = self.0.send(CompositorMsg::AddFontInstance(
font_instance_key, font_instance_key,
font_key, font_key,
size, size,
@ -375,15 +314,11 @@ impl CrossProcessCompositorApi {
} }
pub fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32) { pub fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32) {
let _ = self.0.send(CrossProcessCompositorMessage::AddFont( let _ = self.0.send(CompositorMsg::AddFont(font_key, data, index));
font_key, data, index,
));
} }
pub fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) { pub fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) {
let _ = self.0.send(CrossProcessCompositorMessage::AddSystemFont( let _ = self.0.send(CompositorMsg::AddSystemFont(font_key, handle));
font_key, handle,
));
} }
pub fn fetch_font_keys( pub fn fetch_font_keys(
@ -392,7 +327,7 @@ impl CrossProcessCompositorApi {
number_of_font_instance_keys: usize, number_of_font_instance_keys: usize,
) -> (Vec<FontKey>, Vec<FontInstanceKey>) { ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
let (sender, receiver) = ipc_channel::ipc::channel().expect("Could not create IPC channel"); let (sender, receiver) = ipc_channel::ipc::channel().expect("Could not create IPC channel");
let _ = self.0.send(CrossProcessCompositorMessage::GenerateFontKeys( let _ = self.0.send(CompositorMsg::GenerateFontKeys(
number_of_font_keys, number_of_font_keys,
number_of_font_instance_keys, number_of_font_instance_keys,
sender, sender,