Revert "compositor: Create a single cross-process compositor API (#33619)" (#33645)

This reverts commit f2f5614ad6.

This is causing intermittent crashes: 3104425501

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2024-10-04 11:08:19 +02:00 committed by GitHub
parent 826e31eaa5
commit 48f8ff6236
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 799 additions and 545 deletions

View file

@ -22,10 +22,10 @@ use style::color::AbsoluteColor;
use style::properties::style_structs::Font as FontStyleStruct;
use unicode_script::Script;
use webrender_api::units::{DeviceIntSize, RectExt as RectExt_};
use webrender_api::{ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey};
use webrender_traits::{CrossProcessCompositorApi, ImageUpdate, SerializableImageData};
use webrender_api::{ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey};
use webrender_traits::ImageUpdate;
use crate::canvas_paint_thread::AntialiasMode;
use crate::canvas_paint_thread::{AntialiasMode, WebrenderApi};
use crate::raqote_backend::Repetition;
/// The canvas data stores a state machine for the current status of
@ -428,7 +428,7 @@ pub struct CanvasData<'a> {
path_state: Option<PathState>,
state: CanvasPaintState<'a>,
saved_states: Vec<CanvasPaintState<'a>>,
compositor_api: CrossProcessCompositorApi,
webrender_api: Box<dyn WebrenderApi>,
image_key: Option<ImageKey>,
/// An old webrender image key that can be deleted when the next epoch ends.
old_image_key: Option<ImageKey>,
@ -444,7 +444,7 @@ fn create_backend() -> Box<dyn Backend> {
impl<'a> CanvasData<'a> {
pub fn new(
size: Size2D<u64>,
compositor_api: CrossProcessCompositorApi,
webrender_api: Box<dyn WebrenderApi>,
antialias: AntialiasMode,
font_context: Arc<FontContext>,
) -> CanvasData<'a> {
@ -456,7 +456,7 @@ impl<'a> CanvasData<'a> {
path_state: None,
state: CanvasPaintState::new(antialias),
saved_states: vec![],
compositor_api,
webrender_api,
image_key: None,
old_image_key: None,
very_old_image_key: None,
@ -1279,9 +1279,8 @@ impl<'a> CanvasData<'a> {
offset: 0,
flags: ImageDescriptorFlags::empty(),
};
let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(
&self.drawtarget.snapshot_data_owned(),
));
let data = self.drawtarget.snapshot_data_owned();
let data = ImageData::Raw(Arc::new(data));
let mut updates = vec![];
@ -1291,7 +1290,7 @@ impl<'a> CanvasData<'a> {
updates.push(ImageUpdate::UpdateImage(image_key, descriptor, data));
},
None => {
let Some(key) = self.compositor_api.generate_image_key() else {
let Some(key) = self.webrender_api.generate_key() else {
return;
};
updates.push(ImageUpdate::AddImage(key, descriptor, data));
@ -1306,7 +1305,7 @@ impl<'a> CanvasData<'a> {
updates.push(ImageUpdate::DeleteImage(image_key));
}
self.compositor_api.update_images(updates);
self.webrender_api.update_images(updates);
let data = CanvasImageData {
image_key: self.image_key.unwrap(),
@ -1427,7 +1426,7 @@ impl<'a> Drop for CanvasData<'a> {
updates.push(ImageUpdate::DeleteImage(image_key));
}
self.compositor_api.update_images(updates);
self.webrender_api.update_images(updates);
}
}

View file

@ -16,7 +16,8 @@ use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use log::warn;
use net_traits::ResourceThreads;
use webrender_traits::CrossProcessCompositorApi;
use webrender_api::ImageKey;
use webrender_traits::{ImageUpdate, WebRenderScriptApi};
use crate::canvas_data::*;
@ -25,26 +26,36 @@ pub enum AntialiasMode {
None,
}
pub trait WebrenderApi {
/// Attempt to generate an [`ImageKey`], returning `None` in case of failure.
fn generate_key(&self) -> Option<ImageKey>;
fn update_images(&self, updates: Vec<ImageUpdate>);
fn clone(&self) -> Box<dyn WebrenderApi>;
}
pub struct CanvasPaintThread<'a> {
canvases: HashMap<CanvasId, CanvasData<'a>>,
next_canvas_id: CanvasId,
compositor_api: CrossProcessCompositorApi,
webrender_api: Box<dyn WebrenderApi>,
font_context: Arc<FontContext>,
}
impl<'a> CanvasPaintThread<'a> {
fn new(
compositor_api: CrossProcessCompositorApi,
webrender_api: Box<dyn WebrenderApi>,
system_font_service: Arc<SystemFontServiceProxy>,
resource_threads: ResourceThreads,
) -> CanvasPaintThread<'a> {
// This is only used for web fonts and currently canvas never uses web fonts.
let webrender_script_api = WebRenderScriptApi::dummy();
CanvasPaintThread {
canvases: HashMap::new(),
next_canvas_id: CanvasId(0),
compositor_api: compositor_api.clone(),
webrender_api,
font_context: Arc::new(FontContext::new(
system_font_service,
compositor_api,
webrender_script_api,
resource_threads,
)),
}
@ -53,7 +64,7 @@ impl<'a> CanvasPaintThread<'a> {
/// Creates a new `CanvasPaintThread` and returns an `IpcSender` to
/// communicate with it.
pub fn start(
compositor_api: CrossProcessCompositorApi,
webrender_api: Box<dyn WebrenderApi + Send>,
system_font_service: Arc<SystemFontServiceProxy>,
resource_threads: ResourceThreads,
) -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) {
@ -64,7 +75,7 @@ impl<'a> CanvasPaintThread<'a> {
.name("Canvas".to_owned())
.spawn(move || {
let mut canvas_paint_thread = CanvasPaintThread::new(
compositor_api, system_font_service, resource_threads);
webrender_api, system_font_service, resource_threads);
loop {
select! {
recv(msg_receiver) -> msg => {
@ -130,7 +141,7 @@ impl<'a> CanvasPaintThread<'a> {
let canvas_data = CanvasData::new(
size,
self.compositor_api.clone(),
self.webrender_api.clone(),
antialias,
self.font_context.clone(),
);

View file

@ -16,7 +16,8 @@ use base::cross_process_instant::CrossProcessInstant;
use base::id::{PipelineId, TopLevelBrowsingContextId, WebViewId};
use base::{Epoch, WebRenderEpochToU16};
use compositing_traits::{
CompositionPipeline, CompositorMsg, CompositorReceiver, ConstellationMsg, SendableFrameTree,
CompositionPipeline, CompositorMsg, CompositorReceiver, ConstellationMsg,
ForwardedToCompositorMsg, SendableFrameTree,
};
use crossbeam_channel::Sender;
use embedder_traits::Cursor;
@ -50,7 +51,8 @@ use webrender_api::{
};
use webrender_traits::display_list::{HitTestInfo, ScrollTree};
use webrender_traits::{
CompositorHitTestResult, CrossProcessCompositorMessage, ImageUpdate, RenderingContext,
CanvasToCompositorMsg, CompositorHitTestResult, FontToCompositorMsg, ImageUpdate,
NetToCompositorMsg, RenderingContext, ScriptToCompositorMsg, SerializedImageUpdate,
UntrustedNodeAddress,
};
@ -651,8 +653,29 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.pending_paint_metrics.insert(pipeline_id, epoch);
},
CompositorMsg::CrossProcess(cross_proces_message) => {
self.handle_cross_process_message(cross_proces_message);
CompositorMsg::GetClientWindow(req) => {
if let Err(e) = req.send(self.embedder_coordinates.window) {
warn!("Sending response to get client window failed ({:?}).", e);
}
},
CompositorMsg::GetScreenSize(req) => {
if let Err(e) = req.send(self.embedder_coordinates.screen) {
warn!("Sending response to get screen size failed ({:?}).", e);
}
},
CompositorMsg::GetScreenAvailSize(req) => {
if let Err(e) = req.send(self.embedder_coordinates.screen_avail) {
warn!(
"Sending response to get screen avail size failed ({:?}).",
e
);
}
},
CompositorMsg::Forwarded(msg) => {
self.handle_webrender_message(msg);
},
}
@ -662,9 +685,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
/// Accept messages from content processes that need to be relayed to the WebRender
/// instance in the parent process.
#[tracing::instrument(skip(self), fields(servo_profiling = true))]
fn handle_cross_process_message(&mut self, msg: CrossProcessCompositorMessage) {
fn handle_webrender_message(&mut self, msg: ForwardedToCompositorMsg) {
match msg {
CrossProcessCompositorMessage::SendInitialTransaction(pipeline) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::SendInitialTransaction(
pipeline,
)) => {
let mut txn = Transaction::new();
txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default()));
self.generate_frame(&mut txn, RenderReasons::SCENE);
@ -672,11 +697,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
CrossProcessCompositorMessage::SendScrollNode(
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::SendScrollNode(
pipeline_id,
point,
external_scroll_id,
) => {
)) => {
let pipeline_id = pipeline_id.into();
let pipeline_details = match self.pipeline_details.get_mut(&pipeline_id) {
Some(details) => details,
@ -708,11 +733,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
CrossProcessCompositorMessage::SendDisplayList {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::SendDisplayList {
display_list_info,
display_list_descriptor,
display_list_receiver,
} => {
}) => {
// This must match the order from the sender, currently in `shared/script/lib.rs`.
let items_data = match display_list_receiver.recv() {
Ok(display_list_data) => display_list_data,
@ -768,7 +793,12 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, transaction);
},
CrossProcessCompositorMessage::HitTest(pipeline, point, flags, sender) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::HitTest(
pipeline,
point,
flags,
sender,
)) => {
// 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.
// Without flushing scene building, any hit test we do might be done against
@ -785,20 +815,27 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
let _ = sender.send(result);
},
CrossProcessCompositorMessage::GenerateImageKey(sender) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::GenerateImageKey(sender)) |
ForwardedToCompositorMsg::Net(NetToCompositorMsg::GenerateImageKey(sender)) => {
let _ = sender.send(self.webrender_api.generate_image_key());
},
CrossProcessCompositorMessage::UpdateImages(updates) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::UpdateImages(updates)) => {
let mut txn = Transaction::new();
for update in updates {
match update {
ImageUpdate::AddImage(key, desc, data) => {
txn.add_image(key, desc, data.into(), None)
SerializedImageUpdate::AddImage(key, desc, data) => {
match data.to_image_data() {
Ok(data) => txn.add_image(key, desc, data, None),
Err(e) => warn!("error when sending image data: {:?}", e),
}
},
ImageUpdate::DeleteImage(key) => txn.delete_image(key),
ImageUpdate::UpdateImage(key, desc, data) => {
txn.update_image(key, desc, data.into(), &DirtyRect::All)
SerializedImageUpdate::DeleteImage(key) => txn.delete_image(key),
SerializedImageUpdate::UpdateImage(key, desc, data) => {
match data.to_image_data() {
Ok(data) => txn.update_image(key, desc, data, &DirtyRect::All),
Err(e) => warn!("error when sending image data: {:?}", e),
}
},
}
}
@ -806,27 +843,27 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
CrossProcessCompositorMessage::AddFont(font_key, data, index) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::AddFont(
font_key,
data,
index,
)) => {
self.add_font(font_key, index, data);
},
CrossProcessCompositorMessage::AddSystemFont(font_key, native_handle) => {
let mut transaction = Transaction::new();
transaction.add_native_font(font_key, native_handle);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
},
CrossProcessCompositorMessage::AddFontInstance(
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::AddFontInstance(
font_instance_key,
font_key,
size,
flags,
) => {
)) => {
self.add_font_instance(font_instance_key, font_key, size, flags);
},
CrossProcessCompositorMessage::RemoveFonts(keys, instance_keys) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::RemoveFonts(
keys,
instance_keys,
)) => {
let mut transaction = Transaction::new();
for instance in instance_keys.into_iter() {
@ -840,18 +877,18 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, transaction);
},
CrossProcessCompositorMessage::AddImage(key, desc, data) => {
ForwardedToCompositorMsg::Net(NetToCompositorMsg::AddImage(key, desc, data)) => {
let mut txn = Transaction::new();
txn.add_image(key, desc, data.into(), None);
txn.add_image(key, desc, data, None);
self.webrender_api
.send_transaction(self.webrender_document, txn);
},
CrossProcessCompositorMessage::GenerateFontKeys(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::GenerateKeys(
number_of_font_keys,
number_of_font_instance_keys,
result_sender,
) => {
)) => {
let font_keys = (0..number_of_font_keys)
.map(|_| self.webrender_api.generate_font_key())
.collect();
@ -860,23 +897,53 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.collect();
let _ = result_sender.send((font_keys, font_instance_keys));
},
CrossProcessCompositorMessage::GetClientWindowRect(req) => {
if let Err(e) = req.send(self.embedder_coordinates.window_rect) {
warn!("Sending response to get client window failed ({:?}).", e);
}
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFontInstance(
font_instance_key,
font_key,
size,
flags,
)) => {
self.add_font_instance(font_instance_key, font_key, size, flags);
},
CrossProcessCompositorMessage::GetScreenSize(req) => {
if let Err(e) = req.send(self.embedder_coordinates.screen_size) {
warn!("Sending response to get screen size failed ({:?}).", e);
}
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFont(
font_key,
index,
data,
)) => {
self.add_font(font_key, index, data);
},
CrossProcessCompositorMessage::GetAvailableScreenSize(req) => {
if let Err(e) = req.send(self.embedder_coordinates.available_screen_size) {
warn!(
"Sending response to get screen avail size failed ({:?}).",
e
);
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddSystemFont(
font_key,
native_handle,
)) => {
let mut transaction = Transaction::new();
transaction.add_native_font(font_key, native_handle);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
},
ForwardedToCompositorMsg::Canvas(CanvasToCompositorMsg::GenerateKey(sender)) => {
let _ = sender.send(self.webrender_api.generate_image_key());
},
ForwardedToCompositorMsg::Canvas(CanvasToCompositorMsg::UpdateImages(updates)) => {
let mut txn = Transaction::new();
for update in updates {
match update {
ImageUpdate::AddImage(key, descriptor, data) => {
txn.add_image(key, descriptor, data, None)
},
ImageUpdate::UpdateImage(key, descriptor, data) => {
txn.update_image(key, descriptor, data, &DirtyRect::All)
},
ImageUpdate::DeleteImage(key) => txn.delete_image(key),
}
}
self.webrender_api
.send_transaction(self.webrender_document, txn);
},
}
}
@ -901,40 +968,23 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.remove_pipeline_root_layer(pipeline_id);
let _ = sender.send(());
},
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateImageKey(
sender,
CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas(
CanvasToCompositorMsg::GenerateKey(sender),
)) => {
let _ = sender.send(self.webrender_api.generate_image_key());
},
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GenerateFontKeys(
number_of_font_keys,
number_of_font_instance_keys,
result_sender,
)) => {
let font_keys = (0..number_of_font_keys)
.map(|_| self.webrender_api.generate_font_key())
.collect();
let font_instance_keys = (0..number_of_font_instance_keys)
.map(|_| self.webrender_api.generate_font_instance_key())
.collect();
let _ = result_sender.send((font_keys, font_instance_keys));
},
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetClientWindowRect(
req,
)) => {
if let Err(e) = req.send(self.embedder_coordinates.window_rect) {
CompositorMsg::GetClientWindow(sender) => {
if let Err(e) = sender.send(self.embedder_coordinates.window) {
warn!("Sending response to get client window failed ({:?}).", e);
}
},
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetScreenSize(req)) => {
if let Err(e) = req.send(self.embedder_coordinates.screen_size) {
CompositorMsg::GetScreenSize(sender) => {
if let Err(e) = sender.send(self.embedder_coordinates.screen) {
warn!("Sending response to get screen size failed ({:?}).", e);
}
},
CompositorMsg::CrossProcess(CrossProcessCompositorMessage::GetAvailableScreenSize(
req,
)) => {
if let Err(e) = req.send(self.embedder_coordinates.available_screen_size) {
CompositorMsg::GetScreenAvailSize(sender) => {
if let Err(e) = sender.send(self.embedder_coordinates.screen_avail) {
warn!(
"Sending response to get screen avail size failed ({:?}).",
e

View file

@ -48,7 +48,10 @@ mod from_constellation {
Self::LoadComplete(..) => target!("LoadComplete"),
Self::WebDriverMouseButtonEvent(..) => target!("WebDriverMouseButtonEvent"),
Self::WebDriverMouseMoveEvent(..) => target!("WebDriverMouseMoveEvent"),
Self::CrossProcess(_) => target!("CrossProcess"),
Self::GetClientWindow(..) => target!("GetClientWindow"),
Self::GetScreenSize(..) => target!("GetScreenSize"),
Self::GetScreenAvailSize(..) => target!("GetScreenAvailSize"),
Self::Forwarded(..) => target!("Forwarded"),
}
}
}

View file

@ -241,11 +241,11 @@ pub struct EmbedderCoordinates {
/// The pixel density of the display.
pub hidpi_factor: Scale<f32, DeviceIndependentPixel, DevicePixel>,
/// Size of the screen.
pub screen_size: DeviceIntSize,
pub screen: DeviceIntSize,
/// Size of the available screen space (screen without toolbars and docks).
pub available_screen_size: DeviceIntSize,
/// Position and size of the native window.
pub window_rect: DeviceIntRect,
pub screen_avail: DeviceIntSize,
/// Size of the native window.
pub window: (DeviceIntSize, DeviceIntPoint),
/// Size of the GL buffer in the window.
pub framebuffer: DeviceIntSize,
/// Coordinates of the document within the framebuffer.
@ -290,9 +290,9 @@ mod test {
let screen = Size2D::new(1080, 720);
let coordinates = EmbedderCoordinates {
hidpi_factor: Scale::new(1.),
screen_size: screen,
available_screen_size: screen,
window_rect: DeviceIntRect::from_origin_and_size(pos, viewport),
screen,
screen_avail: screen,
window: (viewport, pos),
framebuffer: viewport,
viewport: DeviceIntRect::from_origin_and_size(pos, viewport),
};

View file

@ -108,7 +108,8 @@ use canvas_traits::canvas::{CanvasId, CanvasMsg};
use canvas_traits::webgl::WebGLThreads;
use canvas_traits::ConstellationCanvasMsg;
use compositing_traits::{
CompositorMsg, CompositorProxy, ConstellationMsg as FromCompositorMsg, SendableFrameTree,
CompositorMsg, CompositorProxy, ConstellationMsg as FromCompositorMsg,
ForwardedToCompositorMsg, SendableFrameTree,
};
use crossbeam_channel::{after, never, select, unbounded, Receiver, Sender};
use devtools_traits::{
@ -156,7 +157,7 @@ use webgpu::swapchain::WGPUImageMap;
use webgpu::{self, WebGPU, WebGPURequest, WebGPUResponse};
use webrender::{RenderApi, RenderApiSender};
use webrender_api::DocumentId;
use webrender_traits::WebrenderExternalImageRegistry;
use webrender_traits::{WebRenderNetApi, WebRenderScriptApi, WebrenderExternalImageRegistry};
use crate::browsingcontext::{
AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator,
@ -391,6 +392,14 @@ pub struct Constellation<STF, SWF> {
/// Webrender related objects required by WebGPU threads
webrender_wgpu: WebrenderWGPU,
/// A channel for content processes to send messages that will
/// be relayed to the WebRender thread.
webrender_api_ipc_sender: WebRenderScriptApi,
/// A channel for content process image caches to send messages
/// that will be relayed to the WebRender thread.
webrender_image_api_sender: WebRenderNetApi,
/// A map of message-port Id to info.
message_ports: HashMap<MessagePortId, MessagePortInfo>,
@ -497,7 +506,7 @@ pub struct InitialConstellationState {
/// A channel through which messages can be sent to the embedder.
pub embedder_proxy: EmbedderProxy,
/// A channel through which messages can be sent to the compositor in-process.
/// A channel through which messages can be sent to the compositor.
pub compositor_proxy: CompositorProxy,
/// A channel to the developer tools, if applicable.
@ -696,6 +705,35 @@ where
// Zero is reserved for the embedder.
PipelineNamespace::install(PipelineNamespaceId(1));
let (webrender_ipc_sender, webrender_ipc_receiver) =
ipc::channel().expect("ipc channel failure");
let (webrender_image_ipc_sender, webrender_image_ipc_receiver) =
ipc::channel().expect("ipc channel failure");
let compositor_proxy = state.compositor_proxy.clone();
ROUTER.add_route(
webrender_ipc_receiver.to_opaque(),
Box::new(move |message| {
compositor_proxy.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::Layout(
message.to().expect("conversion failure"),
),
));
}),
);
let compositor_proxy = state.compositor_proxy.clone();
ROUTER.add_route(
webrender_image_ipc_receiver.to_opaque(),
Box::new(move |message| {
compositor_proxy.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::Net(
message.to().expect("conversion failure"),
),
));
}),
);
let webrender_wgpu = WebrenderWGPU {
webrender_api: state.webrender_api_sender.create_api(),
webrender_external_images: state.webrender_external_images,
@ -750,6 +788,8 @@ where
scheduler_receiver,
document_states: HashMap::new(),
webrender_document: state.webrender_document,
webrender_api_ipc_sender: WebRenderScriptApi::new(webrender_ipc_sender),
webrender_image_api_sender: WebRenderNetApi::new(webrender_image_ipc_sender),
webrender_wgpu,
shutting_down: false,
handled_warnings: VecDeque::new(),
@ -1013,6 +1053,8 @@ where
event_loop,
load_data,
prev_throttled: throttled,
webrender_api_sender: self.webrender_api_ipc_sender.clone(),
webrender_image_api_sender: self.webrender_image_api_sender.clone(),
webrender_document: self.webrender_document,
webgl_chan: self
.webgl_threads
@ -1709,6 +1751,18 @@ where
response_sender.send(true).unwrap_or_default();
},
FromScriptMsg::GetClientWindow(response_sender) => {
self.compositor_proxy
.send(CompositorMsg::GetClientWindow(response_sender));
},
FromScriptMsg::GetScreenSize(response_sender) => {
self.compositor_proxy
.send(CompositorMsg::GetScreenSize(response_sender));
},
FromScriptMsg::GetScreenAvailSize(response_sender) => {
self.compositor_proxy
.send(CompositorMsg::GetScreenAvailSize(response_sender));
},
FromScriptMsg::LogEntry(thread_name, entry) => {
self.handle_log_entry(Some(source_top_ctx_id), thread_name, entry);
},

View file

@ -43,7 +43,6 @@ use servo_config::prefs;
use servo_config::prefs::PrefValue;
use servo_url::ServoUrl;
use webrender_api::DocumentId;
use webrender_traits::CrossProcessCompositorApi;
use crate::event_loop::EventLoop;
use crate::sandboxing::{spawn_multiprocess, UnprivilegedContent};
@ -184,6 +183,12 @@ pub struct InitialPipelineState {
/// compositor threads after spawning a pipeline.
pub prev_throttled: bool,
/// Webrender api.
pub webrender_image_api_sender: webrender_traits::WebRenderNetApi,
/// Webrender api.
pub webrender_api_sender: webrender_traits::WebRenderScriptApi,
/// The ID of the document processed by this script thread.
pub webrender_document: DocumentId,
@ -288,11 +293,9 @@ impl Pipeline {
opts: (*opts::get()).clone(),
prefs: prefs::pref_map().iter().collect(),
pipeline_namespace_id: state.pipeline_namespace_id,
webrender_api_sender: state.webrender_api_sender,
webrender_image_api_sender: state.webrender_image_api_sender,
webrender_document: state.webrender_document,
cross_process_compositor_api: state
.compositor_proxy
.cross_process_compositor_api
.clone(),
webgl_chan: state.webgl_chan,
webxr_registry: state.webxr_registry,
player_context: state.player_context,
@ -495,7 +498,8 @@ pub struct UnprivilegedPipelineContent {
opts: Opts,
prefs: HashMap<String, PrefValue>,
pipeline_namespace_id: PipelineNamespaceId,
cross_process_compositor_api: CrossProcessCompositorApi,
webrender_api_sender: webrender_traits::WebRenderScriptApi,
webrender_image_api_sender: webrender_traits::WebRenderNetApi,
webrender_document: DocumentId,
webgl_chan: Option<WebGLPipeline>,
webxr_registry: webxr_api::Registry,
@ -514,9 +518,7 @@ impl UnprivilegedPipelineContent {
// Idempotent in single-process mode.
PipelineNamespace::set_installer_sender(self.namespace_request_sender);
let image_cache = Arc::new(ImageCacheImpl::new(
self.cross_process_compositor_api.clone(),
));
let image_cache = Arc::new(ImageCacheImpl::new(self.webrender_image_api_sender.clone()));
let (content_process_shutdown_chan, content_process_shutdown_port) = unbounded();
STF::create(
InitialScriptState {
@ -543,7 +545,7 @@ impl UnprivilegedPipelineContent {
webgl_chan: self.webgl_chan,
webxr_registry: self.webxr_registry,
webrender_document: self.webrender_document,
compositor_api: self.cross_process_compositor_api.clone(),
webrender_api_sender: self.webrender_api_sender.clone(),
player_context: self.player_context.clone(),
inherited_secure_context: self.load_data.inherited_secure_context,
},

View file

@ -181,6 +181,9 @@ mod from_script {
Self::PipelineExited => target!("PipelineExited"),
Self::ForwardDOMMessage(..) => target!("ForwardDOMMessage"),
Self::ScheduleJob(..) => target!("ScheduleJob"),
Self::GetClientWindow(..) => target!("GetClientWindow"),
Self::GetScreenSize(..) => target!("GetScreenSize"),
Self::GetScreenAvailSize(..) => target!("GetScreenAvailSize"),
Self::MediaSessionEvent(..) => target!("MediaSessionEvent"),
Self::RequestAdapter(..) => target!("RequestAdapter"),
Self::GetWebGPUChan(..) => target!("GetWebGPUChan"),

View file

@ -30,7 +30,7 @@ use style::values::computed::font::{FamilyName, FontFamilyNameSyntax, SingleFont
use style::Atom;
use url::Url;
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::{ScriptToCompositorMsg, WebRenderScriptApi};
use crate::font::{
Font, FontDescriptor, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope,
@ -52,7 +52,7 @@ pub struct FontContext {
resource_threads: ReentrantMutex<CoreResourceThread>,
/// A sender that can send messages and receive replies from the compositor.
compositor_api: ReentrantMutex<CrossProcessCompositorApi>,
webrender_api: ReentrantMutex<WebRenderScriptApi>,
/// The actual instances of fonts ie a [`FontTemplate`] combined with a size and
/// other font properties, along with the font data and a platform font instance.
@ -100,14 +100,14 @@ impl MallocSizeOf for FontContext {
impl FontContext {
pub fn new(
system_font_service_proxy: Arc<SystemFontServiceProxy>,
compositor_api: CrossProcessCompositorApi,
webrender_api: WebRenderScriptApi,
resource_threads: ResourceThreads,
) -> Self {
#[allow(clippy::default_constructed_unit_structs)]
Self {
system_font_service_proxy,
resource_threads: ReentrantMutex::new(resource_threads.core_thread),
compositor_api: ReentrantMutex::new(compositor_api),
webrender_api: ReentrantMutex::new(webrender_api),
fonts: Default::default(),
resolved_font_groups: Default::default(),
web_fonts: Arc::new(RwLock::default()),
@ -323,11 +323,15 @@ impl FontContext {
.entry(identifier.clone())
.or_insert_with(|| {
let font_key = self.system_font_service_proxy.generate_font_key();
self.compositor_api.lock().add_font(
font_key,
font_data.as_ipc_shared_memory(),
identifier.index(),
);
let _ = self
.webrender_api
.lock()
.sender()
.send(ScriptToCompositorMsg::AddFont(
font_key,
font_data.as_ipc_shared_memory(),
identifier.index(),
));
font_key
});
@ -337,11 +341,13 @@ impl FontContext {
.entry((font_key, pt_size))
.or_insert_with(|| {
let font_instance_key = self.system_font_service_proxy.generate_font_instance_key();
self.compositor_api.lock().add_font_instance(
font_instance_key,
font_key,
pt_size.to_f32_px(),
flags,
let _ = self.webrender_api.lock().sender().send(
ScriptToCompositorMsg::AddFontInstance(
font_instance_key,
font_key,
pt_size.to_f32_px(),
flags,
),
);
font_instance_key
});

View file

@ -27,7 +27,7 @@ use style::values::specified::FontStretch as SpecifiedFontStretch;
use style::Atom;
use tracing::{span, Level};
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderFontApi;
use crate::font::FontDescriptor;
use crate::font_store::FontStore;
@ -97,7 +97,7 @@ struct ResolvedGenericFontFamilies {
pub struct SystemFontService {
port: IpcReceiver<SystemFontServiceMessage>,
local_families: FontStore,
compositor_api: CrossProcessCompositorApi,
webrender_api: Box<dyn WebRenderFontApi>,
webrender_fonts: HashMap<FontIdentifier, FontKey>,
font_instances: HashMap<(FontKey, Au), FontInstanceKey>,
generic_fonts: ResolvedGenericFontFamilies,
@ -129,7 +129,7 @@ impl SystemFontServiceProxySender {
}
impl SystemFontService {
pub fn spawn(compositor_api: CrossProcessCompositorApi) -> SystemFontServiceProxySender {
pub fn spawn(webrender_api: Box<dyn WebRenderFontApi + Send>) -> SystemFontServiceProxySender {
let (sender, receiver) = ipc::channel().unwrap();
thread::Builder::new()
@ -139,7 +139,7 @@ impl SystemFontService {
let mut cache = SystemFontService {
port: receiver,
local_families: Default::default(),
compositor_api,
webrender_api,
webrender_fonts: HashMap::new(),
font_instances: HashMap::new(),
generic_fonts: Default::default(),
@ -198,7 +198,7 @@ impl SystemFontService {
const FREE_FONT_KEYS_BATCH_SIZE: usize = 20;
const FREE_FONT_INSTANCE_KEYS_BATCH_SIZE: usize = 20;
let (mut new_font_keys, mut new_font_instance_keys) = self.compositor_api.fetch_font_keys(
let (mut new_font_keys, mut new_font_instance_keys) = self.webrender_api.fetch_font_keys(
FREE_FONT_KEYS_BATCH_SIZE - self.free_font_keys.len(),
FREE_FONT_INSTANCE_KEYS_BATCH_SIZE - self.free_font_instance_keys.len(),
);
@ -281,7 +281,7 @@ impl SystemFontService {
) -> FontInstanceKey {
self.fetch_new_keys();
let compositor_api = &self.compositor_api;
let webrender_font_api = &self.webrender_api;
let webrender_fonts = &mut self.webrender_fonts;
let font_data = self.local_families.get_or_initialize_font_data(&identifier);
@ -296,12 +296,12 @@ impl SystemFontService {
// this for those platforms.
#[cfg(target_os = "macos")]
if let FontIdentifier::Local(local_font_identifier) = identifier {
compositor_api
webrender_font_api
.add_system_font(font_key, local_font_identifier.native_font_handle());
return font_key;
}
compositor_api.add_font(
webrender_font_api.add_font(
font_key,
font_data.as_ipc_shared_memory(),
identifier.index(),
@ -314,7 +314,7 @@ impl SystemFontService {
.entry((font_key, pt_size))
.or_insert_with(|| {
let font_instance_key = self.free_font_instance_keys.pop().unwrap();
compositor_api.add_font_instance(
webrender_font_api.add_font_instance(
font_instance_key,
font_key,
pt_size.to_f32_px(),

View file

@ -33,7 +33,7 @@ use style::values::computed::{FontLanguageOverride, XLang};
use style::values::generics::font::LineHeight;
use style::ArcSlice;
use webrender_api::{FontInstanceKey, FontKey, IdNamespace};
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderScriptApi;
struct TestContext {
context: FontContext,
@ -47,11 +47,11 @@ impl TestContext {
let (core_sender, _) = ipc::channel().unwrap();
let (storage_sender, _) = ipc::channel().unwrap();
let mock_resource_threads = ResourceThreads::new(core_sender, storage_sender);
let mock_compositor_api = CrossProcessCompositorApi::dummy();
let mock_webrender_api = WebRenderScriptApi::dummy();
let proxy_clone = Arc::new(system_font_service_proxy.to_sender().to_proxy());
Self {
context: FontContext::new(proxy_clone, mock_compositor_api, mock_resource_threads),
context: FontContext::new(proxy_clone, mock_webrender_api, mock_resource_threads),
system_font_service,
system_font_service_proxy,
}

View file

@ -105,7 +105,7 @@ use style_traits::{CSSPixel, DevicePixel, SpeculativePainter};
use time_03::Duration;
use url::Url;
use webrender_api::{units, ColorF, HitTestFlags};
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderScriptApi;
/// Information needed by layout.
pub struct LayoutThread {
@ -170,8 +170,8 @@ pub struct LayoutThread {
/// The executors for paint worklets.
registered_painters: RegisteredPaintersImpl,
/// Cross-process access to the compositor API.
compositor_api: CrossProcessCompositorApi,
/// Webrender interface.
webrender_api: WebRenderScriptApi,
/// Paint time metrics.
paint_time_metrics: PaintTimeMetrics,
@ -201,7 +201,7 @@ impl LayoutFactory for LayoutFactoryImpl {
config.resource_threads,
config.system_font_service,
config.time_profiler_chan,
config.compositor_api,
config.webrender_api_sender,
config.paint_time_metrics,
config.window_size,
))
@ -249,7 +249,7 @@ impl Drop for LayoutThread {
let (keys, instance_keys) = self
.font_context
.collect_unused_webrender_resources(true /* all */);
self.compositor_api
self.webrender_api
.remove_unused_font_resources(keys, instance_keys)
}
}
@ -359,7 +359,7 @@ impl Layout for LayoutThread {
let client_point = units::DevicePoint::from_untyped(point);
let results = self
.compositor_api
.webrender_api
.hit_test(Some(self.id.into()), client_point, flags);
results.iter().map(|result| result.node.into()).collect()
@ -562,12 +562,12 @@ impl LayoutThread {
resource_threads: ResourceThreads,
system_font_service: Arc<SystemFontServiceProxy>,
time_profiler_chan: profile_time::ProfilerChan,
compositor_api: CrossProcessCompositorApi,
webrender_api: WebRenderScriptApi,
paint_time_metrics: PaintTimeMetrics,
window_size: WindowSizeData,
) -> LayoutThread {
// Let webrender know about this pipeline by sending an empty display list.
compositor_api.send_initial_transaction(id.into());
webrender_api.send_initial_transaction(id.into());
let mut font = Font::initial_values();
let default_font_size = pref!(fonts.default_size);
@ -579,7 +579,7 @@ impl LayoutThread {
let font_context = Arc::new(FontContext::new(
system_font_service,
compositor_api.clone(),
webrender_api.clone(),
resource_threads,
));
let device = Device::new(
@ -611,7 +611,7 @@ impl LayoutThread {
Au::from_f32_px(window_size.initial_viewport.width),
Au::from_f32_px(window_size.initial_viewport.height),
),
compositor_api,
webrender_api,
stylist: Stylist::new(device, QuirksMode::NoQuirks),
display_list: Default::default(),
indexable_text: Default::default(),
@ -936,13 +936,13 @@ impl LayoutThread {
self.paint_time_metrics
.maybe_observe_paint_time(self, epoch, is_contentful.0);
self.compositor_api
self.webrender_api
.send_display_list(compositor_info, builder.end().1);
let (keys, instance_keys) = self
.font_context
.collect_unused_webrender_resources(false /* all */);
self.compositor_api
self.webrender_api
.remove_unused_font_resources(keys, instance_keys)
},
);
@ -1185,7 +1185,7 @@ impl LayoutThread {
.insert(state.scroll_id, state.scroll_offset);
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
self.compositor_api.send_scroll_node(
self.webrender_api.send_scroll_node(
self.id.into(),
units::LayoutPoint::from_untyped(point),
state.scroll_id,

View file

@ -92,7 +92,7 @@ use tracing::{span, Level};
use url::Url;
use webrender_api::units::LayoutPixel;
use webrender_api::{units, ExternalScrollId, HitTestFlags};
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderScriptApi;
/// Information needed by layout.
pub struct LayoutThread {
@ -151,8 +151,8 @@ pub struct LayoutThread {
/// The executors for paint worklets.
registered_painters: RegisteredPaintersImpl,
/// Cross-process access to the Compositor API.
compositor_api: CrossProcessCompositorApi,
/// Webrender interface.
webrender_api: WebRenderScriptApi,
/// Paint time metrics.
paint_time_metrics: PaintTimeMetrics,
@ -179,7 +179,7 @@ impl LayoutFactory for LayoutFactoryImpl {
config.resource_threads,
config.system_font_service,
config.time_profiler_chan,
config.compositor_api,
config.webrender_api_sender,
config.paint_time_metrics,
config.window_size,
))
@ -228,7 +228,7 @@ impl Drop for LayoutThread {
let (keys, instance_keys) = self
.font_context
.collect_unused_webrender_resources(true /* all */);
self.compositor_api
self.webrender_api
.remove_unused_font_resources(keys, instance_keys)
}
}
@ -333,7 +333,7 @@ impl Layout for LayoutThread {
let client_point = units::DevicePoint::from_untyped(point);
let results = self
.compositor_api
.webrender_api
.hit_test(Some(self.id.into()), client_point, flags);
results.iter().map(|result| result.node.into()).collect()
@ -504,12 +504,12 @@ impl LayoutThread {
resource_threads: ResourceThreads,
system_font_service: Arc<SystemFontServiceProxy>,
time_profiler_chan: profile_time::ProfilerChan,
compositor_api: CrossProcessCompositorApi,
webrender_api_sender: WebRenderScriptApi,
paint_time_metrics: PaintTimeMetrics,
window_size: WindowSizeData,
) -> LayoutThread {
// Let webrender know about this pipeline by sending an empty display list.
compositor_api.send_initial_transaction(id.into());
webrender_api_sender.send_initial_transaction(id.into());
let mut font = Font::initial_values();
let default_font_size = pref!(fonts.default_size);
@ -523,7 +523,7 @@ impl LayoutThread {
// but it will be set correctly when the initial reflow takes place.
let font_context = Arc::new(FontContext::new(
system_font_service,
compositor_api.clone(),
webrender_api_sender.clone(),
resource_threads,
));
let device = Device::new(
@ -555,7 +555,7 @@ impl LayoutThread {
Au::from_f32_px(window_size.initial_viewport.width),
Au::from_f32_px(window_size.initial_viewport.height),
),
compositor_api,
webrender_api: webrender_api_sender,
scroll_offsets: Default::default(),
stylist: Stylist::new(device, QuirksMode::NoQuirks),
webrender_image_cache: Default::default(),
@ -864,7 +864,7 @@ impl LayoutThread {
.borrow_mut()
.insert(state.scroll_id, state.scroll_offset);
let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y);
self.compositor_api.send_scroll_node(
self.webrender_api.send_scroll_node(
self.id.into(),
units::LayoutPoint::from_untyped(point),
state.scroll_id,
@ -954,13 +954,13 @@ impl LayoutThread {
.maybe_observe_paint_time(self, epoch, is_contentful);
if reflow_goal.needs_display() {
self.compositor_api
self.webrender_api
.send_display_list(display_list.compositor_info, display_list.wr.end().1);
let (keys, instance_keys) = self
.font_context
.collect_unused_webrender_resources(false /* all */);
self.compositor_api
self.webrender_api
.remove_unused_font_resources(keys, instance_keys)
}

View file

@ -10,7 +10,7 @@ use std::{mem, thread};
use embedder_traits::resources::{self, Resource};
use imsz::imsz_from_reader;
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use ipc_channel::ipc::IpcSender;
use log::{debug, warn};
use net_traits::image_cache::{
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponder, ImageResponse,
@ -21,8 +21,8 @@ use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError
use pixels::{load_from_memory, CorsStatus, Image, ImageMetadata, PixelFormat};
use servo_url::{ImmutableOrigin, ServoUrl};
use webrender_api::units::DeviceIntSize;
use webrender_api::{ImageDescriptor, ImageDescriptorFlags, ImageFormat};
use webrender_traits::{CrossProcessCompositorApi, SerializableImageData};
use webrender_api::{ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat};
use webrender_traits::WebRenderNetApi;
use crate::resource_thread::CoreResourceThreadPool;
@ -45,13 +45,13 @@ fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg
DecoderMsg { key, image }
}
fn get_placeholder_image(compositor_api: &CrossProcessCompositorApi, data: &[u8]) -> Arc<Image> {
fn get_placeholder_image(webrender_api: &WebRenderNetApi, data: &[u8]) -> Arc<Image> {
let mut image = load_from_memory(data, CorsStatus::Unsafe).unwrap();
set_webrender_image_key(compositor_api, &mut image);
set_webrender_image_key(webrender_api, &mut image);
Arc::new(image)
}
fn set_webrender_image_key(compositor_api: &CrossProcessCompositorApi, image: &mut Image) {
fn set_webrender_image_key(webrender_api: &WebRenderNetApi, image: &mut Image) {
if image.id.is_some() {
return;
}
@ -82,11 +82,10 @@ fn set_webrender_image_key(compositor_api: &CrossProcessCompositorApi, image: &m
offset: 0,
flags,
};
if let Some(image_key) = compositor_api.generate_image_key() {
let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(&bytes));
compositor_api.add_image(image_key, descriptor, data);
image.id = Some(image_key);
}
let data = ImageData::new(bytes);
let image_key = webrender_api.generate_image_key();
webrender_api.add_image(image_key, descriptor, data);
image.id = Some(image_key);
}
// ======================================================================
@ -329,8 +328,8 @@ struct ImageCacheStore {
// The URL used for the placeholder image
placeholder_url: ServoUrl,
// Cross-process compositor API instance.
compositor_api: CrossProcessCompositorApi,
// Webrender API instance.
webrender_api: WebRenderNetApi,
}
impl ImageCacheStore {
@ -344,7 +343,7 @@ impl ImageCacheStore {
match load_result {
LoadResult::Loaded(ref mut image) => {
set_webrender_image_key(&self.compositor_api, image)
set_webrender_image_key(&self.webrender_api, image)
},
LoadResult::PlaceholderLoaded(..) | LoadResult::None => {},
}
@ -417,7 +416,7 @@ pub struct ImageCacheImpl {
}
impl ImageCache for ImageCacheImpl {
fn new(compositor_api: CrossProcessCompositorApi) -> ImageCacheImpl {
fn new(webrender_api: WebRenderNetApi) -> ImageCacheImpl {
debug!("New image cache");
let rippy_data = resources::read_bytes(Resource::RippyPNG);
@ -432,9 +431,9 @@ impl ImageCache for ImageCacheImpl {
store: Arc::new(Mutex::new(ImageCacheStore {
pending_loads: AllPendingLoads::new(),
completed_loads: HashMap::new(),
placeholder_image: get_placeholder_image(&compositor_api, &rippy_data),
placeholder_image: get_placeholder_image(&webrender_api, &rippy_data),
placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
compositor_api,
webrender_api,
})),
thread_pool: CoreResourceThreadPool::new(thread_count),
}

View file

@ -17,7 +17,7 @@ use headers::{ContentLength, ContentRange, HeaderMapExt};
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
use http::header::{self, HeaderMap, HeaderValue};
use http::StatusCode;
use ipc_channel::ipc::{self, IpcSharedMemory};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use js::jsapi::JSAutoRealm;
use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward, WindowGLContext};
@ -35,10 +35,10 @@ use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, SeekL
use servo_media::{ClientContextId, ServoMedia, SupportsMediaType};
use servo_url::ServoUrl;
use webrender_api::{
ExternalImageData, ExternalImageId, ExternalImageType, ImageBufferKind, ImageDescriptor,
ImageDescriptorFlags, ImageFormat, ImageKey,
ExternalImageData, ExternalImageId, ExternalImageType, ImageBufferKind, ImageData,
ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
};
use webrender_traits::{CrossProcessCompositorApi, ImageUpdate, SerializableImageData};
use webrender_traits::{ImageUpdate, WebRenderScriptApi};
use crate::document_loader::{LoadBlocker, LoadType};
use crate::dom::attr::Attr;
@ -156,7 +156,7 @@ impl FrameHolder {
pub struct MediaFrameRenderer {
player_id: Option<u64>,
compositor_api: CrossProcessCompositorApi,
api: WebRenderScriptApi,
current_frame: Option<(ImageKey, i32, i32)>,
old_frame: Option<ImageKey>,
very_old_frame: Option<ImageKey>,
@ -165,10 +165,10 @@ pub struct MediaFrameRenderer {
}
impl MediaFrameRenderer {
fn new(compositor_api: CrossProcessCompositorApi) -> Self {
fn new(render_api_sender: WebRenderScriptApi) -> Self {
Self {
player_id: None,
compositor_api,
api: render_api_sender,
current_frame: None,
old_frame: None,
very_old_frame: None,
@ -213,7 +213,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
updates.push(ImageUpdate::UpdateImage(
*image_key,
descriptor,
SerializableImageData::Raw(IpcSharedMemory::from_bytes(&frame.get_data())),
ImageData::Raw(frame.get_data()),
));
}
@ -228,7 +228,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
Some((ref mut image_key, ref mut width, ref mut height)) => {
self.old_frame = Some(*image_key);
let Some(new_image_key) = self.compositor_api.generate_image_key() else {
let Some(new_image_key) = self.api.generate_image_key() else {
return;
};
@ -244,13 +244,13 @@ impl VideoFrameRenderer for MediaFrameRenderer {
ImageBufferKind::Texture2D
};
SerializableImageData::External(ExternalImageData {
ImageData::External(ExternalImageData {
id: ExternalImageId(self.player_id.unwrap()),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(texture_target),
})
} else {
SerializableImageData::Raw(IpcSharedMemory::from_bytes(&frame.get_data()))
ImageData::Raw(frame.get_data())
};
self.current_frame_holder
@ -260,7 +260,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
updates.push(ImageUpdate::AddImage(new_image_key, descriptor, image_data));
},
None => {
let Some(image_key) = self.compositor_api.generate_image_key() else {
let Some(image_key) = self.api.generate_image_key() else {
return;
};
self.current_frame = Some((image_key, frame.get_width(), frame.get_height()));
@ -272,13 +272,13 @@ impl VideoFrameRenderer for MediaFrameRenderer {
ImageBufferKind::Texture2D
};
SerializableImageData::External(ExternalImageData {
ImageData::External(ExternalImageData {
id: ExternalImageId(self.player_id.unwrap()),
channel_index: 0,
image_type: ExternalImageType::TextureHandle(texture_target),
})
} else {
SerializableImageData::Raw(IpcSharedMemory::from_bytes(&frame.get_data()))
ImageData::Raw(frame.get_data())
};
self.current_frame_holder = Some(FrameHolder::new(frame));
@ -286,7 +286,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
updates.push(ImageUpdate::AddImage(image_key, descriptor, image_data));
},
}
self.compositor_api.update_images(updates);
self.api.update_images(updates);
}
}
@ -445,7 +445,7 @@ impl HTMLMediaElement {
in_flight_play_promises_queue: Default::default(),
player: Default::default(),
video_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new(
document.window().compositor_api().clone(),
document.window().get_webrender_api_sender(),
))),
audio_renderer: Default::default(),
show_poster: Cell::new(true),

View file

@ -5,14 +5,16 @@
use dom_struct::dom_struct;
use euclid::Size2D;
use profile_traits::ipc;
use script_traits::ScriptMsg;
use style_traits::CSSPixel;
use webrender_api::units::DeviceIntSize;
use webrender_traits::CrossProcessCompositorMessage;
use crate::dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::window::Window;
#[dom_struct]
@ -37,9 +39,9 @@ impl Screen {
let (send, recv) =
ipc::channel::<DeviceIntSize>(self.global().time_profiler_chan().clone()).unwrap();
self.window
.compositor_api()
.sender()
.send(CrossProcessCompositorMessage::GetScreenSize(send))
.upcast::<GlobalScope>()
.script_to_constellation_chan()
.send(ScriptMsg::GetScreenSize(send))
.unwrap();
let dpr = self.window.device_pixel_ratio();
let screen = recv.recv().unwrap_or(Size2D::zero());
@ -50,9 +52,9 @@ impl Screen {
let (send, recv) =
ipc::channel::<DeviceIntSize>(self.global().time_profiler_chan().clone()).unwrap();
self.window
.compositor_api()
.sender()
.send(CrossProcessCompositorMessage::GetAvailableScreenSize(send))
.upcast::<GlobalScope>()
.script_to_constellation_chan()
.send(ScriptMsg::GetScreenAvailSize(send))
.unwrap();
let dpr = self.window.device_pixel_ratio();
let screen = recv.recv().unwrap_or(Size2D::zero());

View file

@ -76,9 +76,9 @@ use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::{CssRuleType, Origin, UrlExtraData};
use style_traits::{CSSPixel, DevicePixel, ParsingMode};
use url::Position;
use webrender_api::units::{DeviceIntRect, LayoutPixel};
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel};
use webrender_api::{DocumentId, ExternalScrollId};
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderScriptApi;
use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
use super::bindings::trace::HashMapTracedValues;
@ -312,10 +312,10 @@ pub struct Window {
/// Flag to identify whether mutation observers are present(true)/absent(false)
exists_mut_observer: Cell<bool>,
/// Cross-process access to the compositor.
/// Webrender API Sender
#[ignore_malloc_size_of = "Wraps an IpcSender"]
#[no_trace]
compositor_api: CrossProcessCompositorApi,
webrender_api_sender: WebRenderScriptApi,
/// Indicate whether a SetDocumentStatus message has been sent after a reflow is complete.
/// It is used to avoid sending idle message more than once, which is unneccessary.
@ -526,8 +526,8 @@ impl Window {
self.add_pending_reflow();
}
pub fn compositor_api(&self) -> &CrossProcessCompositorApi {
&self.compositor_api
pub fn get_webrender_api_sender(&self) -> WebRenderScriptApi {
self.webrender_api_sender.clone()
}
pub fn get_userscripts_path(&self) -> Option<String> {
@ -1773,16 +1773,14 @@ impl Window {
fn client_window(&self) -> (Size2D<u32, CSSPixel>, Point2D<i32, CSSPixel>) {
let timer_profile_chan = self.global().time_profiler_chan().clone();
let (send, recv) = ProfiledIpc::channel::<DeviceIntRect>(timer_profile_chan).unwrap();
let _ = self
.compositor_api
.sender()
.send(webrender_traits::CrossProcessCompositorMessage::GetClientWindowRect(send));
let rect = recv.recv().unwrap_or_default();
let (send, recv) =
ProfiledIpc::channel::<(DeviceIntSize, DeviceIntPoint)>(timer_profile_chan).unwrap();
self.send_to_constellation(ScriptMsg::GetClientWindow(send));
let (size, point) = recv.recv().unwrap_or((Size2D::zero(), Point2D::zero()));
let dpr = self.device_pixel_ratio();
(
(rect.size().to_f32() / dpr).to_u32(),
(rect.min.to_f32() / dpr).to_i32(),
(size.to_f32() / dpr).to_u32(),
(point.to_f32() / dpr).to_i32(),
)
}
@ -2550,7 +2548,7 @@ impl Window {
webxr_registry: webxr_api::Registry,
microtask_queue: Rc<MicrotaskQueue>,
webrender_document: DocumentId,
compositor_api: CrossProcessCompositorApi,
webrender_api_sender: WebRenderScriptApi,
relayout_event: bool,
prepare_for_screenshot: bool,
unminify_js: bool,
@ -2635,7 +2633,7 @@ impl Window {
paint_worklet: Default::default(),
webrender_document,
exists_mut_observer: Cell::new(false),
compositor_api,
webrender_api_sender,
has_sent_idle_message: Cell::new(false),
relayout_event,
prepare_for_screenshot,

View file

@ -95,7 +95,7 @@ use style::thread_state::{self, ThreadState};
use url::Position;
use webgpu::{WebGPUDevice, WebGPUMsg};
use webrender_api::DocumentId;
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderScriptApi;
use crate::document_loader::DocumentLoader;
use crate::dom::bindings::cell::DomRefCell;
@ -669,9 +669,9 @@ pub struct ScriptThread {
#[no_trace]
webrender_document: DocumentId,
/// Cross-process access to the compositor's API.
/// Webrender API sender.
#[no_trace]
compositor_api: CrossProcessCompositorApi,
webrender_api_sender: WebRenderScriptApi,
/// Periodically print out on which events script threads spend their processing time.
profile_script_events: bool,
@ -1399,7 +1399,7 @@ impl ScriptThread {
custom_element_reaction_stack: CustomElementReactionStack::new(),
webrender_document: state.webrender_document,
compositor_api: state.compositor_api,
webrender_api_sender: state.webrender_api_sender,
profile_script_events: opts.debug.profile_script_events,
print_pwm: opts.print_pwm,
@ -3661,7 +3661,7 @@ impl ScriptThread {
system_font_service: self.system_font_service.clone(),
resource_threads: self.resource_threads.clone(),
time_profiler_chan: self.time_profiler_chan.clone(),
compositor_api: self.compositor_api.clone(),
webrender_api_sender: self.webrender_api_sender.clone(),
paint_time_metrics,
window_size: incomplete.window_size,
};
@ -3692,7 +3692,7 @@ impl ScriptThread {
self.webxr_registry.clone(),
self.microtask_queue.clone(),
self.webrender_document,
self.compositor_api.clone(),
self.webrender_api_sender.clone(),
self.relayout_event,
self.prepare_for_screenshot,
self.unminify_js,

View file

@ -28,13 +28,15 @@ pub use base::id::TopLevelBrowsingContextId;
use base::id::{PipelineNamespace, PipelineNamespaceId};
use bluetooth::BluetoothThreadFactory;
use bluetooth_traits::BluetoothRequest;
use canvas::canvas_paint_thread::CanvasPaintThread;
use canvas::canvas_paint_thread::{self, CanvasPaintThread};
use canvas::WebGLComm;
use canvas_traits::webgl::WebGLThreads;
use compositing::webview::UnknownWebView;
use compositing::windowing::{EmbedderEvent, EmbedderMethods, WindowMethods};
use compositing::{CompositeTarget, IOCompositor, InitialCompositorState, ShutdownState};
use compositing_traits::{CompositorMsg, CompositorProxy, CompositorReceiver, ConstellationMsg};
use compositing_traits::{
CompositorMsg, CompositorProxy, CompositorReceiver, ConstellationMsg, ForwardedToCompositorMsg,
};
#[cfg(all(
not(target_os = "windows"),
not(target_os = "ios"),
@ -64,8 +66,7 @@ use fonts::SystemFontService;
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
pub use gleam::gl;
use gleam::gl::RENDERER;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
#[cfg(feature = "layout_2013")]
pub use layout_thread_2013;
use log::{error, trace, warn, Log, Metadata, Record};
@ -90,10 +91,13 @@ use surfman::{GLApi, GLVersion};
use surfman::{NativeConnection, NativeContext};
use webgpu::swapchain::WGPUImageMap;
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
use webrender_api::{ColorF, DocumentId, FramePublishId};
use webrender_api::{
ColorF, DocumentId, FontInstanceFlags, FontInstanceKey, FontKey, FramePublishId, ImageKey,
NativeFontHandle,
};
use webrender_traits::{
CrossProcessCompositorApi, RenderingContext, WebrenderExternalImageHandlers,
WebrenderExternalImageRegistry, WebrenderImageHandlerType,
CanvasToCompositorMsg, FontToCompositorMsg, ImageUpdate, RenderingContext, WebRenderFontApi,
WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, WebrenderImageHandlerType,
};
pub use {
background_hang_monitor, base, bluetooth, bluetooth_traits, canvas, canvas_traits, compositing,
@ -975,24 +979,9 @@ 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 sender_clone = sender.clone();
ROUTER.add_route(
compositor_ipc_receiver.to_opaque(),
Box::new(move |message| {
let _ = sender_clone.send(CompositorMsg::CrossProcess(
message.to().expect("Could not convert Compositor message"),
));
}),
);
let cross_process_compositor_api = CrossProcessCompositorApi(compositor_ipc_sender);
(
CompositorProxy {
sender,
cross_process_compositor_api,
event_loop_waker,
},
CompositorReceiver { receiver },
@ -1054,11 +1043,14 @@ fn create_constellation(
);
let system_font_service = Arc::new(
SystemFontService::spawn(compositor_proxy.cross_process_compositor_api.clone()).to_proxy(),
SystemFontService::spawn(Box::new(WebRenderFontApiCompositorProxy(
compositor_proxy.clone(),
)))
.to_proxy(),
);
let (canvas_create_sender, canvas_ipc_sender) = CanvasPaintThread::start(
compositor_proxy.cross_process_compositor_api.clone(),
Box::new(CanvasWebrenderApi(compositor_proxy.clone())),
system_font_service.clone(),
public_resource_threads.clone(),
);
@ -1102,6 +1094,82 @@ fn create_constellation(
)
}
struct WebRenderFontApiCompositorProxy(CompositorProxy);
impl WebRenderFontApi for WebRenderFontApiCompositorProxy {
fn add_font_instance(
&self,
font_instance_key: FontInstanceKey,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
) {
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFontInstance(
font_instance_key,
font_key,
size,
flags,
)),
));
}
fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32) {
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFont(
font_key, index, data,
)),
));
}
fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) {
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddSystemFont(
font_key, handle,
)),
));
}
fn fetch_font_keys(
&self,
number_of_font_keys: usize,
number_of_font_instance_keys: usize,
) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
let (sender, receiver) = unbounded();
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::GenerateKeys(
number_of_font_keys,
number_of_font_instance_keys,
sender,
)),
));
receiver.recv().unwrap()
}
}
#[derive(Clone)]
struct CanvasWebrenderApi(CompositorProxy);
impl canvas_paint_thread::WebrenderApi for CanvasWebrenderApi {
fn generate_key(&self) -> Option<ImageKey> {
let (sender, receiver) = unbounded();
self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas(
CanvasToCompositorMsg::GenerateKey(sender),
)));
receiver.recv().ok()
}
fn update_images(&self, updates: Vec<ImageUpdate>) {
self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas(
CanvasToCompositorMsg::UpdateImages(updates),
)));
}
fn clone(&self) -> Box<dyn canvas_paint_thread::WebrenderApi> {
Box::new(<Self as Clone>::clone(self))
}
}
// A logger that logs to two downstream loggers.
// This should probably be in the log crate.
struct BothLogger<Log1, Log2>(Log1, Log2);

View file

@ -21,18 +21,15 @@ use script_traits::{
AnimationState, ConstellationControlMsg, EventResult, MouseButton, MouseEventType,
};
use style_traits::CSSPixel;
use webrender_api::units::DeviceRect;
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DeviceRect};
use webrender_api::DocumentId;
use webrender_traits::{CrossProcessCompositorApi, CrossProcessCompositorMessage};
use webrender_traits::{
CanvasToCompositorMsg, FontToCompositorMsg, NetToCompositorMsg, ScriptToCompositorMsg,
};
/// 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>,
}
@ -45,6 +42,15 @@ 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>,
@ -108,9 +114,16 @@ 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.
CrossProcess(CrossProcessCompositorMessage),
Forwarded(ForwardedToCompositorMsg),
}
pub struct SendableFrameTree {
@ -126,6 +139,27 @@ 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 {
@ -149,7 +183,10 @@ impl Debug for CompositorMsg {
CompositorMsg::LoadComplete(..) => write!(f, "LoadComplete"),
CompositorMsg::WebDriverMouseButtonEvent(..) => write!(f, "WebDriverMouseButtonEvent"),
CompositorMsg::WebDriverMouseMoveEvent(..) => write!(f, "WebDriverMouseMoveEvent"),
CompositorMsg::CrossProcess(..) => write!(f, "CrossProcess"),
CompositorMsg::GetClientWindow(..) => write!(f, "GetClientWindow"),
CompositorMsg::GetScreenSize(..) => write!(f, "GetScreenSize"),
CompositorMsg::GetScreenAvailSize(..) => write!(f, "GetScreenAvailSize"),
CompositorMsg::Forwarded(..) => write!(f, "Webrender"),
}
}
}

View file

@ -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::CrossProcessCompositorApi;
use webrender_traits::WebRenderNetApi;
use crate::request::CorsSettings;
use crate::FetchResponseMsg;
@ -99,7 +99,7 @@ pub enum ImageCacheResult {
}
pub trait ImageCache: Sync + Send {
fn new(compositor_api: CrossProcessCompositorApi) -> Self
fn new(webrender_api: WebRenderNetApi) -> Self
where
Self: Sized;

View file

@ -58,9 +58,7 @@ use style_traits::{CSSPixel, SpeculativePainter};
use webgpu::WebGPUMsg;
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel};
use webrender_api::{DocumentId, ExternalScrollId, ImageKey};
use webrender_traits::{
CrossProcessCompositorApi, UntrustedNodeAddress as WebRenderUntrustedNodeAddress,
};
use webrender_traits::{UntrustedNodeAddress as WebRenderUntrustedNodeAddress, WebRenderScriptApi};
pub use crate::script_msg::{
DOMMessage, EventResult, HistoryEntryReplacement, IFrameSizeMsg, Job, JobError, JobResult,
@ -661,8 +659,8 @@ pub struct InitialScriptState {
pub webxr_registry: webxr_api::Registry,
/// The Webrender document ID associated with this thread.
pub webrender_document: DocumentId,
/// Access to the compositor across a process boundary.
pub compositor_api: CrossProcessCompositorApi,
/// FIXME(victor): The Webrender API sender in this constellation's pipeline
pub webrender_api_sender: WebRenderScriptApi,
/// Application window's GL Context for Media player
pub player_context: WindowGLContext,
}

View file

@ -24,6 +24,7 @@ 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,
@ -244,6 +245,12 @@ 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),
@ -311,6 +318,9 @@ impl fmt::Debug for ScriptMsg {
PipelineExited => "PipelineExited",
ForwardDOMMessage(..) => "ForwardDOMMessage",
ScheduleJob(..) => "ScheduleJob",
GetClientWindow(..) => "GetClientWindow",
GetScreenSize(..) => "GetScreenSize",
GetScreenAvailSize(..) => "GetScreenAvailSize",
MediaSessionEvent(..) => "MediaSessionEvent",
RequestAdapter(..) => "RequestAdapter",
GetWebGPUChan(..) => "GetWebGPUChan",

View file

@ -53,7 +53,7 @@ use style::stylesheets::Stylesheet;
use style::Atom;
use style_traits::CSSPixel;
use webrender_api::ImageKey;
use webrender_traits::CrossProcessCompositorApi;
use webrender_traits::WebRenderScriptApi;
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 compositor_api: CrossProcessCompositorApi,
pub webrender_api_sender: WebRenderScriptApi,
pub paint_time_metrics: PaintTimeMetrics,
pub window_size: WindowSizeData,
}

View file

@ -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::{DeviceIntRect, DeviceIntSize, DevicePoint, LayoutPoint, TexelRect};
use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect};
use webrender_api::{
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
ExternalImageHandler, ExternalImageId, ExternalImageSource, ExternalScrollId,
@ -29,261 +29,6 @@ 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: 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,
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.
@ -438,34 +183,304 @@ 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: 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,
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, SerializableImageData),
AddImage(ImageKey, ImageDescriptor, ImageData),
/// Delete a previously registered image registration.
DeleteImage(ImageKey),
/// Update an existing image registration.
UpdateImage(ImageKey, ImageDescriptor, SerializableImageData),
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),
}
#[derive(Debug, Deserialize, Serialize)]
/// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too
/// slow.
pub enum SerializableImageData {
pub enum SerializedImageData {
/// A simple series of bytes, provided by the embedding and owned by WebRender.
/// The format is stored out-of-band, currently in ImageDescriptor.
Raw(IpcSharedMemory),
Raw(ipc::IpcBytesReceiver),
/// 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 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),
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)),
}
}
}

View file

@ -536,10 +536,10 @@ impl WindowMethods for Window {
EmbedderCoordinates {
viewport,
framebuffer: viewport.size(),
window_rect: DeviceIntRect::from_origin_and_size(window_origin, window_size),
screen_size: screen,
window: (window_size, window_origin),
screen,
// FIXME: Winit doesn't have API for available size. Fallback to screen size
available_screen_size: screen,
screen_avail: screen,
hidpi_factor: self.hidpi_factor(),
}
}

View file

@ -167,9 +167,9 @@ impl WindowMethods for Window {
EmbedderCoordinates {
viewport,
framebuffer: size,
window_rect: DeviceIntRect::from_origin_and_size(Point2D::zero(), size),
screen_size: size,
available_screen_size: size,
window: (size, Point2D::zero()),
screen: size,
screen_avail: size,
hidpi_factor: dpr,
}
}

View file

@ -25,7 +25,6 @@ use servo::script_traits::{
};
use servo::servo_url::ServoUrl;
use servo::style_traits::DevicePixel;
use servo::webrender_api::units::DeviceIntRect;
use servo::webrender_api::ScrollLocation;
use servo::webrender_traits::RenderingContext;
use servo::{gl, Servo, TopLevelBrowsingContextId};
@ -694,9 +693,9 @@ impl WindowMethods for ServoWindowCallbacks {
EmbedderCoordinates {
viewport: coords.viewport.to_box2d(),
framebuffer: coords.framebuffer,
window_rect: DeviceIntRect::from_origin_and_size(Point2D::zero(), coords.viewport.size),
screen_size: coords.viewport.size,
available_screen_size: coords.viewport.size,
window: (coords.viewport.size, Point2D::new(0, 0)),
screen: coords.viewport.size,
screen_avail: coords.viewport.size,
hidpi_factor: Scale::new(self.density),
}
}