mirror of
https://github.com/servo/servo.git
synced 2025-07-22 06:43:40 +01:00
Instead of exposing many different kinds of messages to the compositor that are routed through the constellation, expose a single message type which can be sent across IPC channels. In addition, this IPC channel and the route to the crossbeam channel with the compositor is created along with the `CompositorProxy`, simplifying what needs to be passed around during pipeline initialization. Previously, some image updates (from video) were sent over IPC with a special serialization routine and some were sent via crossbeam channels (canvas). Now all updates go over the IPC channel `IpcSharedMemory` is used to avoid serialization penalties. This should improve performance and reduce copies for video, but add a memory copy overhead for canvas. This will improve in the future when canvas renders directly into a texture. All-in-all this is a simplification which opens the path toward having a standard compositor API and reduces the number of duplicate messages and proxying that had to happen in libservo. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
30cbf01280
commit
9195344b75
28 changed files with 547 additions and 800 deletions
|
@ -21,15 +21,18 @@ use script_traits::{
|
|||
AnimationState, ConstellationControlMsg, EventResult, MouseButton, MouseEventType,
|
||||
};
|
||||
use style_traits::CSSPixel;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DeviceRect};
|
||||
use webrender_api::units::DeviceRect;
|
||||
use webrender_api::DocumentId;
|
||||
use webrender_traits::{
|
||||
CanvasToCompositorMsg, FontToCompositorMsg, NetToCompositorMsg, ScriptToCompositorMsg,
|
||||
};
|
||||
use webrender_traits::{CrossProcessCompositorApi, CrossProcessCompositorMessage};
|
||||
|
||||
/// Sends messages to the compositor.
|
||||
#[derive(Clone)]
|
||||
pub struct CompositorProxy {
|
||||
pub sender: Sender<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>,
|
||||
}
|
||||
|
||||
|
@ -42,15 +45,6 @@ impl CompositorProxy {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clone for CompositorProxy {
|
||||
fn clone(&self) -> CompositorProxy {
|
||||
CompositorProxy {
|
||||
sender: self.sender.clone(),
|
||||
event_loop_waker: self.event_loop_waker.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The port that the compositor receives messages on.
|
||||
pub struct CompositorReceiver {
|
||||
pub receiver: Receiver<CompositorMsg>,
|
||||
|
@ -114,16 +108,9 @@ pub enum CompositorMsg {
|
|||
/// WebDriver mouse move event
|
||||
WebDriverMouseMoveEvent(f32, f32),
|
||||
|
||||
/// Get Window Informations size and position.
|
||||
GetClientWindow(IpcSender<(DeviceIntSize, DeviceIntPoint)>),
|
||||
/// Get screen size.
|
||||
GetScreenSize(IpcSender<DeviceIntSize>),
|
||||
/// Get screen available size.
|
||||
GetScreenAvailSize(IpcSender<DeviceIntSize>),
|
||||
|
||||
/// Messages forwarded to the compositor by the constellation from other crates. These
|
||||
/// messages are mainly passed on from the compositor to WebRender.
|
||||
Forwarded(ForwardedToCompositorMsg),
|
||||
CrossProcess(CrossProcessCompositorMessage),
|
||||
}
|
||||
|
||||
pub struct SendableFrameTree {
|
||||
|
@ -139,27 +126,6 @@ pub struct CompositionPipeline {
|
|||
pub script_chan: IpcSender<ConstellationControlMsg>,
|
||||
}
|
||||
|
||||
/// Messages forwarded by the Constellation to the Compositor.
|
||||
pub enum ForwardedToCompositorMsg {
|
||||
Layout(ScriptToCompositorMsg),
|
||||
Net(NetToCompositorMsg),
|
||||
SystemFontService(FontToCompositorMsg),
|
||||
Canvas(CanvasToCompositorMsg),
|
||||
}
|
||||
|
||||
impl Debug for ForwardedToCompositorMsg {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
match self {
|
||||
ForwardedToCompositorMsg::Layout(_) => write!(f, "Layout(ScriptToCompositorMsg)"),
|
||||
ForwardedToCompositorMsg::Net(_) => write!(f, "Net(NetToCompositorMsg)"),
|
||||
ForwardedToCompositorMsg::SystemFontService(_) => {
|
||||
write!(f, "SystemFontService(FontToCompositorMsg)")
|
||||
},
|
||||
ForwardedToCompositorMsg::Canvas(_) => write!(f, "Canvas(CanvasToCompositorMsg)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for CompositorMsg {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
match *self {
|
||||
|
@ -183,10 +149,7 @@ impl Debug for CompositorMsg {
|
|||
CompositorMsg::LoadComplete(..) => write!(f, "LoadComplete"),
|
||||
CompositorMsg::WebDriverMouseButtonEvent(..) => write!(f, "WebDriverMouseButtonEvent"),
|
||||
CompositorMsg::WebDriverMouseMoveEvent(..) => write!(f, "WebDriverMouseMoveEvent"),
|
||||
CompositorMsg::GetClientWindow(..) => write!(f, "GetClientWindow"),
|
||||
CompositorMsg::GetScreenSize(..) => write!(f, "GetScreenSize"),
|
||||
CompositorMsg::GetScreenAvailSize(..) => write!(f, "GetScreenAvailSize"),
|
||||
CompositorMsg::Forwarded(..) => write!(f, "Webrender"),
|
||||
CompositorMsg::CrossProcess(..) => write!(f, "CrossProcess"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use malloc_size_of_derive::MallocSizeOf;
|
|||
use pixels::{Image, ImageMetadata};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use webrender_traits::WebRenderNetApi;
|
||||
use webrender_traits::CrossProcessCompositorApi;
|
||||
|
||||
use crate::request::CorsSettings;
|
||||
use crate::FetchResponseMsg;
|
||||
|
@ -99,7 +99,7 @@ pub enum ImageCacheResult {
|
|||
}
|
||||
|
||||
pub trait ImageCache: Sync + Send {
|
||||
fn new(webrender_api: WebRenderNetApi) -> Self
|
||||
fn new(compositor_api: CrossProcessCompositorApi) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
|
|
|
@ -58,7 +58,9 @@ use style_traits::{CSSPixel, SpeculativePainter};
|
|||
use webgpu::WebGPUMsg;
|
||||
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel};
|
||||
use webrender_api::{DocumentId, ExternalScrollId, ImageKey};
|
||||
use webrender_traits::{UntrustedNodeAddress as WebRenderUntrustedNodeAddress, WebRenderScriptApi};
|
||||
use webrender_traits::{
|
||||
CrossProcessCompositorApi, UntrustedNodeAddress as WebRenderUntrustedNodeAddress,
|
||||
};
|
||||
|
||||
pub use crate::script_msg::{
|
||||
DOMMessage, EventResult, HistoryEntryReplacement, IFrameSizeMsg, Job, JobError, JobResult,
|
||||
|
@ -659,8 +661,8 @@ pub struct InitialScriptState {
|
|||
pub webxr_registry: webxr_api::Registry,
|
||||
/// The Webrender document ID associated with this thread.
|
||||
pub webrender_document: DocumentId,
|
||||
/// FIXME(victor): The Webrender API sender in this constellation's pipeline
|
||||
pub webrender_api_sender: WebRenderScriptApi,
|
||||
/// Access to the compositor across a process boundary.
|
||||
pub compositor_api: CrossProcessCompositorApi,
|
||||
/// Application window's GL Context for Media player
|
||||
pub player_context: WindowGLContext,
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ use serde::{Deserialize, Serialize};
|
|||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use style_traits::CSSPixel;
|
||||
use webgpu::{wgc, WebGPU, WebGPUResponse};
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||
|
||||
use crate::{
|
||||
AnimationState, AuxiliaryBrowsingContextLoadInfo, BroadcastMsg, DocumentState,
|
||||
|
@ -245,12 +244,6 @@ pub enum ScriptMsg {
|
|||
ForwardDOMMessage(DOMMessage, ServoUrl),
|
||||
/// <https://w3c.github.io/ServiceWorker/#schedule-job-algorithm>
|
||||
ScheduleJob(Job),
|
||||
/// Get Window Informations size and position
|
||||
GetClientWindow(IpcSender<(DeviceIntSize, DeviceIntPoint)>),
|
||||
/// Get the screen size (pixel)
|
||||
GetScreenSize(IpcSender<DeviceIntSize>),
|
||||
/// Get the available screen size (pixel)
|
||||
GetScreenAvailSize(IpcSender<DeviceIntSize>),
|
||||
/// Notifies the constellation about media session events
|
||||
/// (i.e. when there is metadata for the active media session, playback state changes...).
|
||||
MediaSessionEvent(PipelineId, MediaSessionEvent),
|
||||
|
@ -318,9 +311,6 @@ impl fmt::Debug for ScriptMsg {
|
|||
PipelineExited => "PipelineExited",
|
||||
ForwardDOMMessage(..) => "ForwardDOMMessage",
|
||||
ScheduleJob(..) => "ScheduleJob",
|
||||
GetClientWindow(..) => "GetClientWindow",
|
||||
GetScreenSize(..) => "GetScreenSize",
|
||||
GetScreenAvailSize(..) => "GetScreenAvailSize",
|
||||
MediaSessionEvent(..) => "MediaSessionEvent",
|
||||
RequestAdapter(..) => "RequestAdapter",
|
||||
GetWebGPUChan(..) => "GetWebGPUChan",
|
||||
|
|
|
@ -53,7 +53,7 @@ use style::stylesheets::Stylesheet;
|
|||
use style::Atom;
|
||||
use style_traits::CSSPixel;
|
||||
use webrender_api::ImageKey;
|
||||
use webrender_traits::WebRenderScriptApi;
|
||||
use webrender_traits::CrossProcessCompositorApi;
|
||||
|
||||
pub type GenericLayoutData = dyn Any + Send + Sync;
|
||||
|
||||
|
@ -177,7 +177,7 @@ pub struct LayoutConfig {
|
|||
pub resource_threads: ResourceThreads,
|
||||
pub system_font_service: Arc<SystemFontServiceProxy>,
|
||||
pub time_profiler_chan: time::ProfilerChan,
|
||||
pub webrender_api_sender: WebRenderScriptApi,
|
||||
pub compositor_api: CrossProcessCompositorApi,
|
||||
pub paint_time_metrics: PaintTimeMetrics,
|
||||
pub window_size: WindowSizeData,
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
pub mod display_list;
|
||||
pub mod rendering_context;
|
||||
|
||||
use core::fmt;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use base::id::PipelineId;
|
||||
use crossbeam_channel::Sender;
|
||||
use display_list::{CompositorDisplayListInfo, ScrollTreeNodeId};
|
||||
use embedder_traits::Cursor;
|
||||
use euclid::default::Size2D;
|
||||
|
@ -19,7 +19,7 @@ use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
|
|||
use libc::c_void;
|
||||
use log::warn;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
|
||||
use webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePoint, LayoutPoint, TexelRect};
|
||||
use webrender_api::{
|
||||
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
|
||||
ExternalImageHandler, ExternalImageId, ExternalImageSource, ExternalScrollId,
|
||||
|
@ -29,6 +29,261 @@ use webrender_api::{
|
|||
|
||||
pub use crate::rendering_context::RenderingContext;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum CrossProcessCompositorMessage {
|
||||
/// Inform WebRender of the existence of this pipeline.
|
||||
SendInitialTransaction(WebRenderPipelineId),
|
||||
/// Perform a scroll operation.
|
||||
SendScrollNode(WebRenderPipelineId, LayoutPoint, ExternalScrollId),
|
||||
/// Inform WebRender of a new display list for the given pipeline.
|
||||
SendDisplayList {
|
||||
/// The [CompositorDisplayListInfo] that describes the display list being sent.
|
||||
display_list_info: Box<CompositorDisplayListInfo>,
|
||||
/// A descriptor of this display list used to construct this display list from raw data.
|
||||
display_list_descriptor: BuiltDisplayListDescriptor,
|
||||
/// An [ipc::IpcBytesReceiver] used to send the raw data of the display list.
|
||||
display_list_receiver: ipc::IpcBytesReceiver,
|
||||
},
|
||||
/// Perform a hit test operation. The result will be returned via
|
||||
/// the provided channel sender.
|
||||
HitTest(
|
||||
Option<WebRenderPipelineId>,
|
||||
DevicePoint,
|
||||
HitTestFlags,
|
||||
IpcSender<Vec<CompositorHitTestResult>>,
|
||||
),
|
||||
/// Create a new image key. The result will be returned via the
|
||||
/// provided channel sender.
|
||||
GenerateImageKey(IpcSender<ImageKey>),
|
||||
/// Add an image with the given data and `ImageKey`.
|
||||
AddImage(ImageKey, ImageDescriptor, SerializableImageData),
|
||||
/// Perform a resource update operation.
|
||||
UpdateImages(Vec<ImageUpdate>),
|
||||
|
||||
/// Generate a new batch of font keys which can be used to allocate
|
||||
/// keys asynchronously.
|
||||
GenerateFontKeys(
|
||||
usize,
|
||||
usize,
|
||||
IpcSender<(Vec<FontKey>, Vec<FontInstanceKey>)>,
|
||||
),
|
||||
/// Add a font with the given data and font key.
|
||||
AddFont(FontKey, Arc<IpcSharedMemory>, u32),
|
||||
/// Add a system font with the given font key and handle.
|
||||
AddSystemFont(FontKey, NativeFontHandle),
|
||||
/// Add an instance of a font with the given instance key.
|
||||
AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
|
||||
/// Remove the given font resources from our WebRender instance.
|
||||
RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
|
||||
|
||||
/// Get the client window size and position.
|
||||
GetClientWindowRect(IpcSender<DeviceIntRect>),
|
||||
/// Get the size of the screen that the client window inhabits.
|
||||
GetScreenSize(IpcSender<DeviceIntSize>),
|
||||
/// Get the available screen size (without toolbars and docks) for the screen
|
||||
/// the client window inhabits.
|
||||
GetAvailableScreenSize(IpcSender<DeviceIntSize>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for CrossProcessCompositorMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::AddImage(..) => f.write_str("AddImage"),
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mechanism to send messages from ScriptThread to the parent process' WebRender instance.
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct CrossProcessCompositorApi(pub IpcSender<CrossProcessCompositorMessage>);
|
||||
|
||||
impl CrossProcessCompositorApi {
|
||||
/// Create a new [`CrossProcessCompositorApi`] struct that does not have a listener on the other
|
||||
/// end to use for unit testing.
|
||||
pub fn dummy() -> Self {
|
||||
let (sender, _) = ipc::channel().unwrap();
|
||||
Self(sender)
|
||||
}
|
||||
|
||||
/// Get the sender for this proxy.
|
||||
pub fn sender(&self) -> &IpcSender<CrossProcessCompositorMessage> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Inform WebRender of the existence of this pipeline.
|
||||
pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) {
|
||||
if let Err(e) = self
|
||||
.0
|
||||
.send(CrossProcessCompositorMessage::SendInitialTransaction(
|
||||
pipeline,
|
||||
))
|
||||
{
|
||||
warn!("Error sending initial transaction: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a scroll operation.
|
||||
pub fn send_scroll_node(
|
||||
&self,
|
||||
pipeline_id: WebRenderPipelineId,
|
||||
point: LayoutPoint,
|
||||
scroll_id: ExternalScrollId,
|
||||
) {
|
||||
if let Err(e) = self.0.send(CrossProcessCompositorMessage::SendScrollNode(
|
||||
pipeline_id,
|
||||
point,
|
||||
scroll_id,
|
||||
)) {
|
||||
warn!("Error sending scroll node: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inform WebRender of a new display list for the given pipeline.
|
||||
pub fn send_display_list(
|
||||
&self,
|
||||
display_list_info: CompositorDisplayListInfo,
|
||||
list: BuiltDisplayList,
|
||||
) {
|
||||
let (display_list_data, display_list_descriptor) = list.into_data();
|
||||
let (display_list_sender, display_list_receiver) = ipc::bytes_channel().unwrap();
|
||||
if let Err(e) = self.0.send(CrossProcessCompositorMessage::SendDisplayList {
|
||||
display_list_info: Box::new(display_list_info),
|
||||
display_list_descriptor,
|
||||
display_list_receiver,
|
||||
}) {
|
||||
warn!("Error sending display list: {}", e);
|
||||
}
|
||||
|
||||
if let Err(error) = display_list_sender.send(&display_list_data.items_data) {
|
||||
warn!("Error sending display list items: {}", error);
|
||||
}
|
||||
if let Err(error) = display_list_sender.send(&display_list_data.cache_data) {
|
||||
warn!("Error sending display list cache data: {}", error);
|
||||
}
|
||||
if let Err(error) = display_list_sender.send(&display_list_data.spatial_tree) {
|
||||
warn!("Error sending display spatial tree: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a hit test operation. Blocks until the operation is complete and
|
||||
/// and a result is available.
|
||||
pub fn hit_test(
|
||||
&self,
|
||||
pipeline: Option<WebRenderPipelineId>,
|
||||
point: DevicePoint,
|
||||
flags: HitTestFlags,
|
||||
) -> Vec<CompositorHitTestResult> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.0
|
||||
.send(CrossProcessCompositorMessage::HitTest(
|
||||
pipeline, point, flags, sender,
|
||||
))
|
||||
.expect("error sending hit test");
|
||||
receiver.recv().expect("error receiving hit test result")
|
||||
}
|
||||
|
||||
/// Create a new image key. Blocks until the key is available.
|
||||
pub fn generate_image_key(&self) -> Option<ImageKey> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.0
|
||||
.send(CrossProcessCompositorMessage::GenerateImageKey(sender))
|
||||
.ok()?;
|
||||
receiver.recv().ok()
|
||||
}
|
||||
|
||||
pub fn add_image(
|
||||
&self,
|
||||
key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: SerializableImageData,
|
||||
) {
|
||||
if let Err(e) = self.0.send(CrossProcessCompositorMessage::AddImage(
|
||||
key, descriptor, data,
|
||||
)) {
|
||||
warn!("Error sending image update: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform an image resource update operation.
|
||||
pub fn update_images(&self, updates: Vec<ImageUpdate>) {
|
||||
if let Err(e) = self
|
||||
.0
|
||||
.send(CrossProcessCompositorMessage::UpdateImages(updates))
|
||||
{
|
||||
warn!("error sending image updates: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_unused_font_resources(
|
||||
&self,
|
||||
keys: Vec<FontKey>,
|
||||
instance_keys: Vec<FontInstanceKey>,
|
||||
) {
|
||||
if keys.is_empty() && instance_keys.is_empty() {
|
||||
return;
|
||||
}
|
||||
let _ = self.0.send(CrossProcessCompositorMessage::RemoveFonts(
|
||||
keys,
|
||||
instance_keys,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn add_font_instance(
|
||||
&self,
|
||||
font_instance_key: FontInstanceKey,
|
||||
font_key: FontKey,
|
||||
size: f32,
|
||||
flags: FontInstanceFlags,
|
||||
) {
|
||||
let _x = self.0.send(CrossProcessCompositorMessage::AddFontInstance(
|
||||
font_instance_key,
|
||||
font_key,
|
||||
size,
|
||||
flags,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32) {
|
||||
let _ = self.0.send(CrossProcessCompositorMessage::AddFont(
|
||||
font_key, data, index,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) {
|
||||
let _ = self.0.send(CrossProcessCompositorMessage::AddSystemFont(
|
||||
font_key, handle,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn fetch_font_keys(
|
||||
&self,
|
||||
number_of_font_keys: usize,
|
||||
number_of_font_instance_keys: usize,
|
||||
) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
|
||||
let (sender, receiver) = ipc_channel::ipc::channel().expect("Could not create IPC channel");
|
||||
let _ = self.0.send(CrossProcessCompositorMessage::GenerateFontKeys(
|
||||
number_of_font_keys,
|
||||
number_of_font_instance_keys,
|
||||
sender,
|
||||
));
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is used as a bridge between the different GL clients
|
||||
/// in Servo that handles WebRender ExternalImages and the WebRender
|
||||
/// ExternalImageHandler API.
|
||||
|
@ -183,303 +438,34 @@ impl ExternalImageHandler for WebrenderExternalImageHandlers {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait WebRenderFontApi {
|
||||
fn add_font_instance(
|
||||
&self,
|
||||
font_instance_key: FontInstanceKey,
|
||||
font_key: FontKey,
|
||||
size: f32,
|
||||
flags: FontInstanceFlags,
|
||||
);
|
||||
fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32);
|
||||
fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle);
|
||||
fn fetch_font_keys(
|
||||
&self,
|
||||
number_of_font_keys: usize,
|
||||
number_of_font_instance_keys: usize,
|
||||
) -> (Vec<FontKey>, Vec<FontInstanceKey>);
|
||||
}
|
||||
|
||||
pub enum CanvasToCompositorMsg {
|
||||
GenerateKey(Sender<ImageKey>),
|
||||
UpdateImages(Vec<ImageUpdate>),
|
||||
}
|
||||
|
||||
pub enum FontToCompositorMsg {
|
||||
GenerateKeys(usize, usize, Sender<(Vec<FontKey>, Vec<FontInstanceKey>)>),
|
||||
AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
|
||||
AddFont(FontKey, u32, Arc<IpcSharedMemory>),
|
||||
AddSystemFont(FontKey, NativeFontHandle),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum NetToCompositorMsg {
|
||||
AddImage(ImageKey, ImageDescriptor, ImageData),
|
||||
GenerateImageKey(IpcSender<ImageKey>),
|
||||
}
|
||||
|
||||
/// The set of WebRender operations that can be initiated by the content process.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum ScriptToCompositorMsg {
|
||||
/// Inform WebRender of the existence of this pipeline.
|
||||
SendInitialTransaction(WebRenderPipelineId),
|
||||
/// Perform a scroll operation.
|
||||
SendScrollNode(WebRenderPipelineId, LayoutPoint, ExternalScrollId),
|
||||
/// Inform WebRender of a new display list for the given pipeline.
|
||||
SendDisplayList {
|
||||
/// The [CompositorDisplayListInfo] that describes the display list being sent.
|
||||
display_list_info: Box<CompositorDisplayListInfo>,
|
||||
/// A descriptor of this display list used to construct this display list from raw data.
|
||||
display_list_descriptor: BuiltDisplayListDescriptor,
|
||||
/// An [ipc::IpcBytesReceiver] used to send the raw data of the display list.
|
||||
display_list_receiver: ipc::IpcBytesReceiver,
|
||||
},
|
||||
/// Perform a hit test operation. The result will be returned via
|
||||
/// the provided channel sender.
|
||||
HitTest(
|
||||
Option<WebRenderPipelineId>,
|
||||
DevicePoint,
|
||||
HitTestFlags,
|
||||
IpcSender<Vec<CompositorHitTestResult>>,
|
||||
),
|
||||
/// Create a new image key. The result will be returned via the
|
||||
/// provided channel sender.
|
||||
GenerateImageKey(IpcSender<ImageKey>),
|
||||
/// Perform a resource update operation.
|
||||
UpdateImages(Vec<SerializedImageUpdate>),
|
||||
/// Remove the given font resources from our WebRender instance.
|
||||
RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
|
||||
AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
|
||||
AddFont(FontKey, Arc<IpcSharedMemory>, u32),
|
||||
}
|
||||
|
||||
/// A mechanism to send messages from networking to the WebRender instance.
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct WebRenderNetApi(IpcSender<NetToCompositorMsg>);
|
||||
|
||||
impl WebRenderNetApi {
|
||||
pub fn new(sender: IpcSender<NetToCompositorMsg>) -> Self {
|
||||
Self(sender)
|
||||
}
|
||||
|
||||
pub fn generate_image_key(&self) -> ImageKey {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.0
|
||||
.send(NetToCompositorMsg::GenerateImageKey(sender))
|
||||
.expect("error sending image key generation");
|
||||
receiver.recv().expect("error receiving image key result")
|
||||
}
|
||||
|
||||
pub fn add_image(&self, key: ImageKey, descriptor: ImageDescriptor, data: ImageData) {
|
||||
if let Err(e) = self
|
||||
.0
|
||||
.send(NetToCompositorMsg::AddImage(key, descriptor, data))
|
||||
{
|
||||
warn!("Error sending image update: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mechanism to send messages from ScriptThread to the parent process' WebRender instance.
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct WebRenderScriptApi(IpcSender<ScriptToCompositorMsg>);
|
||||
|
||||
impl WebRenderScriptApi {
|
||||
/// Create a new [`WebRenderScriptApi`] object that wraps the provided channel sender.
|
||||
pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> Self {
|
||||
Self(sender)
|
||||
}
|
||||
|
||||
/// Create a new [`WebRenderScriptApi`] object that does not have a listener on the
|
||||
/// other end.
|
||||
pub fn dummy() -> Self {
|
||||
let (sender, _) = ipc::channel().unwrap();
|
||||
Self::new(sender)
|
||||
}
|
||||
|
||||
/// Get the sender for this proxy.
|
||||
pub fn sender(&self) -> &IpcSender<ScriptToCompositorMsg> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Inform WebRender of the existence of this pipeline.
|
||||
pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) {
|
||||
if let Err(e) = self
|
||||
.0
|
||||
.send(ScriptToCompositorMsg::SendInitialTransaction(pipeline))
|
||||
{
|
||||
warn!("Error sending initial transaction: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a scroll operation.
|
||||
pub fn send_scroll_node(
|
||||
&self,
|
||||
pipeline_id: WebRenderPipelineId,
|
||||
point: LayoutPoint,
|
||||
scroll_id: ExternalScrollId,
|
||||
) {
|
||||
if let Err(e) = self.0.send(ScriptToCompositorMsg::SendScrollNode(
|
||||
pipeline_id,
|
||||
point,
|
||||
scroll_id,
|
||||
)) {
|
||||
warn!("Error sending scroll node: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inform WebRender of a new display list for the given pipeline.
|
||||
pub fn send_display_list(
|
||||
&self,
|
||||
display_list_info: CompositorDisplayListInfo,
|
||||
list: BuiltDisplayList,
|
||||
) {
|
||||
let (display_list_data, display_list_descriptor) = list.into_data();
|
||||
let (display_list_sender, display_list_receiver) = ipc::bytes_channel().unwrap();
|
||||
if let Err(e) = self.0.send(ScriptToCompositorMsg::SendDisplayList {
|
||||
display_list_info: Box::new(display_list_info),
|
||||
display_list_descriptor,
|
||||
display_list_receiver,
|
||||
}) {
|
||||
warn!("Error sending display list: {}", e);
|
||||
}
|
||||
if let Err(error) = display_list_sender.send(&display_list_data.items_data) {
|
||||
warn!("Error sending display list items: {}", error);
|
||||
}
|
||||
if let Err(error) = display_list_sender.send(&display_list_data.cache_data) {
|
||||
warn!("Error sending display list cache data: {}", error);
|
||||
}
|
||||
if let Err(error) = display_list_sender.send(&display_list_data.spatial_tree) {
|
||||
warn!("Error sending display spatial tree: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a hit test operation. Blocks until the operation is complete and
|
||||
/// and a result is available.
|
||||
pub fn hit_test(
|
||||
&self,
|
||||
pipeline: Option<WebRenderPipelineId>,
|
||||
point: DevicePoint,
|
||||
flags: HitTestFlags,
|
||||
) -> Vec<CompositorHitTestResult> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.0
|
||||
.send(ScriptToCompositorMsg::HitTest(
|
||||
pipeline, point, flags, sender,
|
||||
))
|
||||
.expect("error sending hit test");
|
||||
receiver.recv().expect("error receiving hit test result")
|
||||
}
|
||||
|
||||
/// Create a new image key. Blocks until the key is available.
|
||||
pub fn generate_image_key(&self) -> Option<ImageKey> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.0
|
||||
.send(ScriptToCompositorMsg::GenerateImageKey(sender))
|
||||
.ok()?;
|
||||
receiver.recv().ok()
|
||||
}
|
||||
|
||||
/// Perform a resource update operation.
|
||||
pub fn update_images(&self, updates: Vec<ImageUpdate>) {
|
||||
let mut senders = Vec::new();
|
||||
// Convert `ImageUpdate` to `SerializedImageUpdate` because `ImageData` may contain large
|
||||
// byes. With this conversion, we send `IpcBytesReceiver` instead and use it to send the
|
||||
// actual bytes.
|
||||
let updates = updates
|
||||
.into_iter()
|
||||
.map(|update| match update {
|
||||
ImageUpdate::AddImage(k, d, data) => {
|
||||
let data = match data {
|
||||
ImageData::Raw(r) => {
|
||||
let (sender, receiver) = ipc::bytes_channel().unwrap();
|
||||
senders.push((sender, r));
|
||||
SerializedImageData::Raw(receiver)
|
||||
},
|
||||
ImageData::External(e) => SerializedImageData::External(e),
|
||||
};
|
||||
SerializedImageUpdate::AddImage(k, d, data)
|
||||
},
|
||||
ImageUpdate::DeleteImage(k) => SerializedImageUpdate::DeleteImage(k),
|
||||
ImageUpdate::UpdateImage(k, d, data) => {
|
||||
let data = match data {
|
||||
ImageData::Raw(r) => {
|
||||
let (sender, receiver) = ipc::bytes_channel().unwrap();
|
||||
senders.push((sender, r));
|
||||
SerializedImageData::Raw(receiver)
|
||||
},
|
||||
ImageData::External(e) => SerializedImageData::External(e),
|
||||
};
|
||||
SerializedImageUpdate::UpdateImage(k, d, data)
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Err(e) = self.0.send(ScriptToCompositorMsg::UpdateImages(updates)) {
|
||||
warn!("error sending image updates: {}", e);
|
||||
}
|
||||
|
||||
senders.into_iter().for_each(|(tx, data)| {
|
||||
if let Err(e) = tx.send(&data) {
|
||||
warn!("error sending image data: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn remove_unused_font_resources(
|
||||
&self,
|
||||
keys: Vec<FontKey>,
|
||||
instance_keys: Vec<FontInstanceKey>,
|
||||
) {
|
||||
if keys.is_empty() && instance_keys.is_empty() {
|
||||
return;
|
||||
}
|
||||
let _ = self
|
||||
.0
|
||||
.send(ScriptToCompositorMsg::RemoveFonts(keys, instance_keys));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
/// Serializable image updates that must be performed by WebRender.
|
||||
pub enum ImageUpdate {
|
||||
/// Register a new image.
|
||||
AddImage(ImageKey, ImageDescriptor, ImageData),
|
||||
AddImage(ImageKey, ImageDescriptor, SerializableImageData),
|
||||
/// Delete a previously registered image registration.
|
||||
DeleteImage(ImageKey),
|
||||
/// Update an existing image registration.
|
||||
UpdateImage(ImageKey, ImageDescriptor, ImageData),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
/// Serialized `ImageUpdate`.
|
||||
pub enum SerializedImageUpdate {
|
||||
/// Register a new image.
|
||||
AddImage(ImageKey, ImageDescriptor, SerializedImageData),
|
||||
/// Delete a previously registered image registration.
|
||||
DeleteImage(ImageKey),
|
||||
/// Update an existing image registration.
|
||||
UpdateImage(ImageKey, ImageDescriptor, SerializedImageData),
|
||||
UpdateImage(ImageKey, ImageDescriptor, SerializableImageData),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
/// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too
|
||||
/// slow.
|
||||
pub enum SerializedImageData {
|
||||
pub enum SerializableImageData {
|
||||
/// A simple series of bytes, provided by the embedding and owned by WebRender.
|
||||
/// The format is stored out-of-band, currently in ImageDescriptor.
|
||||
Raw(ipc::IpcBytesReceiver),
|
||||
Raw(IpcSharedMemory),
|
||||
/// An image owned by the embedding, and referenced by WebRender. This may
|
||||
/// take the form of a texture or a heap-allocated buffer.
|
||||
External(ExternalImageData),
|
||||
}
|
||||
|
||||
impl SerializedImageData {
|
||||
/// Convert to ``ImageData`.
|
||||
pub fn to_image_data(&self) -> Result<ImageData, ipc::IpcError> {
|
||||
match self {
|
||||
SerializedImageData::Raw(rx) => rx.recv().map(ImageData::new),
|
||||
SerializedImageData::External(image) => Ok(ImageData::External(*image)),
|
||||
impl From<SerializableImageData> for ImageData {
|
||||
fn from(value: SerializableImageData) -> Self {
|
||||
match value {
|
||||
SerializableImageData::Raw(shared_memory) => ImageData::new(shared_memory.to_vec()),
|
||||
SerializableImageData::External(image) => ImageData::External(image),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue