diff options
author | Mukilan Thiyagarajan <mukilan@igalia.com> | 2024-05-20 16:05:18 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-20 10:35:18 +0000 |
commit | 2af6fe0b30a275e5fd8a43eca4126d82639fbaa9 (patch) | |
tree | 2687a12c392b30cba7cdcd849133d0d382b79cbe /components/shared | |
parent | c2076580f352f3c61f90969e03d78ada609935eb (diff) | |
download | servo-2af6fe0b30a275e5fd8a43eca4126d82639fbaa9.tar.gz servo-2af6fe0b30a275e5fd8a43eca4126d82639fbaa9.zip |
compositor: Move WebRender-ish messages and types to `webrender_traits` (#32315)
* Move WebRender related types to `webrender_traits`
This refactor moves several WebRender related types
from `compositing_traits`, `script_traits` and `net_traits`
crates to the `webrender_traits` crate.
This change also moves the `Image` type and associated
function out of `net_traits` and into the `pixels` crate.
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
* Move `script_traits::WebrenderIpcSender` to `webrender_traits::WebRenderScriptApi`
---------
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Diffstat (limited to 'components/shared')
-rw-r--r-- | components/shared/compositing/Cargo.toml | 4 | ||||
-rw-r--r-- | components/shared/compositing/lib.rs | 20 | ||||
-rw-r--r-- | components/shared/net/Cargo.toml | 1 | ||||
-rw-r--r-- | components/shared/net/image/base.rs | 121 | ||||
-rw-r--r-- | components/shared/net/image_cache.rs | 18 | ||||
-rw-r--r-- | components/shared/net/lib.rs | 43 | ||||
-rw-r--r-- | components/shared/net/tests/image.rs | 28 | ||||
-rw-r--r-- | components/shared/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/shared/script/lib.rs | 259 | ||||
-rw-r--r-- | components/shared/script/tests/compositor.rs | 6 | ||||
-rw-r--r-- | components/shared/script_layout/Cargo.toml | 2 | ||||
-rw-r--r-- | components/shared/script_layout/lib.rs | 5 | ||||
-rw-r--r-- | components/shared/script_layout/wrapper_traits.rs | 2 | ||||
-rw-r--r-- | components/shared/webrender/Cargo.toml | 7 | ||||
-rw-r--r-- | components/shared/webrender/display_list.rs (renamed from components/shared/script/compositor.rs) | 0 | ||||
-rw-r--r-- | components/shared/webrender/lib.rs | 324 |
16 files changed, 361 insertions, 480 deletions
diff --git a/components/shared/compositing/Cargo.toml b/components/shared/compositing/Cargo.toml index aed9a0e3565..b454cae37fa 100644 --- a/components/shared/compositing/Cargo.toml +++ b/components/shared/compositing/Cargo.toml @@ -12,7 +12,6 @@ path = "lib.rs" [dependencies] base = { workspace = true } -canvas = { path = "../../canvas" } crossbeam-channel = { workspace = true } embedder_traits = { workspace = true } euclid = { workspace = true } @@ -20,8 +19,9 @@ gfx_traits = { workspace = true } ipc-channel = { workspace = true } keyboard-types = { workspace = true } log = { workspace = true } -net_traits = { workspace = true } +pixels = { path = '../../pixels' } script_traits = { workspace = true } servo_url = { path = "../../url" } style_traits = { workspace = true } webrender_api = { workspace = true } +webrender_traits = { workspace = true } diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index 34c390cca85..171b0676c2d 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -10,23 +10,20 @@ use std::fmt::{Debug, Error, Formatter}; use base::id::{PipelineId, TopLevelBrowsingContextId}; use base::Epoch; -use canvas::canvas_paint_thread::ImageUpdate; pub use constellation_msg::ConstellationMsg; use crossbeam_channel::{Receiver, Sender}; use embedder_traits::EventLoopWaker; use euclid::Rect; use ipc_channel::ipc::IpcSender; use log::warn; -use net_traits::image::base::Image; -use net_traits::NetToCompositorMsg; +use pixels::Image; use script_traits::{ AnimationState, ConstellationControlMsg, EventResult, MouseButton, MouseEventType, - ScriptToCompositorMsg, }; use style_traits::CSSPixel; use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DeviceRect}; -use webrender_api::{ - self, FontInstanceFlags, FontInstanceKey, FontKey, ImageKey, NativeFontHandle, +use webrender_traits::{ + CanvasToCompositorMsg, FontToCompositorMsg, NetToCompositorMsg, ScriptToCompositorMsg, }; /// Sends messages to the compositor. @@ -140,17 +137,6 @@ pub struct CompositionPipeline { pub script_chan: IpcSender<ConstellationControlMsg>, } -pub enum FontToCompositorMsg { - AddFontInstance(FontKey, f32, FontInstanceFlags, Sender<FontInstanceKey>), - AddFont(Sender<FontKey>, u32, ipc_channel::ipc::IpcBytesReceiver), - AddSystemFont(Sender<FontKey>, NativeFontHandle), -} - -pub enum CanvasToCompositorMsg { - GenerateKey(Sender<ImageKey>), - UpdateImages(Vec<ImageUpdate>), -} - /// Messages forwarded by the Constellation to the Compositor. pub enum ForwardedToCompositorMsg { Layout(ScriptToCompositorMsg), diff --git a/components/shared/net/Cargo.toml b/components/shared/net/Cargo.toml index 73db752aba6..cf174100feb 100644 --- a/components/shared/net/Cargo.toml +++ b/components/shared/net/Cargo.toml @@ -39,3 +39,4 @@ servo_url = { path = "../../url" } url = { workspace = true } uuid = { workspace = true } webrender_api = { workspace = true } +webrender_traits = { workspace = true } diff --git a/components/shared/net/image/base.rs b/components/shared/net/image/base.rs deleted file mode 100644 index 66257012df2..00000000000 --- a/components/shared/net/image/base.rs +++ /dev/null @@ -1,121 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -use std::fmt; - -use image::ImageFormat; -use ipc_channel::ipc::IpcSharedMemory; -use log::debug; -use malloc_size_of_derive::MallocSizeOf; -use pixels::PixelFormat; -use serde::{Deserialize, Serialize}; -use webrender_api::ImageKey; - -use crate::image_cache::CorsStatus; - -#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] -pub struct Image { - pub width: u32, - pub height: u32, - pub format: PixelFormat, - #[ignore_malloc_size_of = "Defined in ipc-channel"] - pub bytes: IpcSharedMemory, - #[ignore_malloc_size_of = "Defined in webrender_api"] - pub id: Option<ImageKey>, - pub cors_status: CorsStatus, -} - -impl fmt::Debug for Image { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Image {{ width: {}, height: {}, format: {:?}, ..., id: {:?} }}", - self.width, self.height, self.format, self.id - ) - } -} - -#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] -pub struct ImageMetadata { - pub width: u32, - pub height: u32, -} - -// FIXME: Images must not be copied every frame. Instead we should atomically -// reference count them. - -pub fn load_from_memory(buffer: &[u8], cors_status: CorsStatus) -> Option<Image> { - if buffer.is_empty() { - return None; - } - - let image_fmt_result = detect_image_format(buffer); - match image_fmt_result { - Err(msg) => { - debug!("{}", msg); - None - }, - Ok(_) => match image::load_from_memory(buffer) { - Ok(image) => { - let mut rgba = image.into_rgba8(); - pixels::rgba8_byte_swap_colors_inplace(&mut rgba); - Some(Image { - width: rgba.width(), - height: rgba.height(), - format: PixelFormat::BGRA8, - bytes: IpcSharedMemory::from_bytes(&rgba), - id: None, - cors_status, - }) - }, - Err(e) => { - debug!("Image decoding error: {:?}", e); - None - }, - }, - } -} - -// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img -pub fn detect_image_format(buffer: &[u8]) -> Result<ImageFormat, &str> { - if is_gif(buffer) { - Ok(ImageFormat::Gif) - } else if is_jpeg(buffer) { - Ok(ImageFormat::Jpeg) - } else if is_png(buffer) { - Ok(ImageFormat::Png) - } else if is_webp(buffer) { - Ok(ImageFormat::WebP) - } else if is_bmp(buffer) { - Ok(ImageFormat::Bmp) - } else if is_ico(buffer) { - Ok(ImageFormat::Ico) - } else { - Err("Image Format Not Supported") - } -} - -fn is_gif(buffer: &[u8]) -> bool { - buffer.starts_with(b"GIF87a") || buffer.starts_with(b"GIF89a") -} - -fn is_jpeg(buffer: &[u8]) -> bool { - buffer.starts_with(&[0xff, 0xd8, 0xff]) -} - -fn is_png(buffer: &[u8]) -> bool { - buffer.starts_with(&[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) -} - -fn is_bmp(buffer: &[u8]) -> bool { - buffer.starts_with(&[0x42, 0x4D]) -} - -fn is_ico(buffer: &[u8]) -> bool { - buffer.starts_with(&[0x00, 0x00, 0x01, 0x00]) -} - -fn is_webp(buffer: &[u8]) -> bool { - buffer.starts_with(b"RIFF") && buffer.len() >= 14 && &buffer[8..14] == b"WEBPVP" -} diff --git a/components/shared/net/image_cache.rs b/components/shared/net/image_cache.rs index d1087bace63..317fd1b66ef 100644 --- a/components/shared/net/image_cache.rs +++ b/components/shared/net/image_cache.rs @@ -7,12 +7,13 @@ use std::sync::Arc; use ipc_channel::ipc::IpcSender; use log::debug; use malloc_size_of_derive::MallocSizeOf; +use pixels::{Image, ImageMetadata}; use serde::{Deserialize, Serialize}; use servo_url::{ImmutableOrigin, ServoUrl}; +use webrender_traits::WebRenderNetApi; -use crate::image::base::{Image, ImageMetadata}; use crate::request::CorsSettings; -use crate::{FetchResponseMsg, WebrenderIpcSender}; +use crate::FetchResponseMsg; // ====================================================================== // Aux structs and enums. @@ -98,7 +99,7 @@ pub enum ImageCacheResult { } pub trait ImageCache: Sync + Send { - fn new(webrender_api: WebrenderIpcSender) -> Self + fn new(webrender_api: WebRenderNetApi) -> Self where Self: Sized; @@ -140,14 +141,3 @@ pub trait ImageCache: Sync + Send { /// Inform the image cache about a response for a pending request. fn notify_pending_response(&self, id: PendingImageId, action: FetchResponseMsg); } - -/// Whether this response passed any CORS checks, and is thus safe to read from -/// in cross-origin environments. -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] -pub enum CorsStatus { - /// The response is either same-origin or cross-origin but passed CORS checks. - Safe, - /// The response is cross-origin and did not pass CORS checks. It is unsafe - /// to expose pixel data to the requesting environment. - Unsafe, -} diff --git a/components/shared/net/lib.rs b/components/shared/net/lib.rs index 436ccf5d645..595d47c7b06 100644 --- a/components/shared/net/lib.rs +++ b/components/shared/net/lib.rs @@ -16,7 +16,6 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use ipc_channel::Error as IpcError; use lazy_static::lazy_static; -use log::warn; use malloc_size_of::malloc_size_of_is_0; use malloc_size_of_derive::MallocSizeOf; use mime::Mime; @@ -25,7 +24,6 @@ use rustls::Certificate; use serde::{Deserialize, Serialize}; use servo_rand::RngCore; use servo_url::{ImmutableOrigin, ServoUrl}; -use webrender_api::{ImageData, ImageDescriptor, ImageKey}; use crate::filemanager_thread::FileManagerThreadMsg; use crate::request::{Request, RequestBuilder}; @@ -41,15 +39,6 @@ pub mod request; pub mod response; pub mod storage_thread; -/// Image handling. -/// -/// It may be surprising that this goes in the network crate as opposed to the graphics crate. -/// However, image handling is generally very integrated with the network stack (especially where -/// caching is involved) and as a result it must live in here. -pub mod image { - pub mod base; -} - /// An implementation of the [Fetch specification](https://fetch.spec.whatwg.org/) pub mod fetch { pub mod headers; @@ -829,38 +818,6 @@ pub fn http_percent_encode(bytes: &[u8]) -> String { percent_encoding::percent_encode(bytes, HTTP_VALUE).to_string() } -#[derive(Deserialize, Serialize)] -pub enum NetToCompositorMsg { - AddImage(ImageKey, ImageDescriptor, ImageData), - GenerateImageKey(IpcSender<ImageKey>), -} - -#[derive(Clone, Deserialize, Serialize)] -pub struct WebrenderIpcSender(IpcSender<NetToCompositorMsg>); - -impl WebrenderIpcSender { - 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); - } - } -} - lazy_static! { pub static ref PRIVILEGED_SECRET: u32 = servo_rand::ServoRng::default().next_u32(); } diff --git a/components/shared/net/tests/image.rs b/components/shared/net/tests/image.rs deleted file mode 100644 index a4963702b57..00000000000 --- a/components/shared/net/tests/image.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -use net_traits::image::base::detect_image_format; - -#[test] -fn test_supported_images() { - let gif1 = [b'G', b'I', b'F', b'8', b'7', b'a']; - let gif2 = [b'G', b'I', b'F', b'8', b'9', b'a']; - let jpeg = [0xff, 0xd8, 0xff]; - let png = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; - let webp = [ - b'R', b'I', b'F', b'F', 0x01, 0x02, 0x03, 0x04, b'W', b'E', b'B', b'P', b'V', b'P', - ]; - let bmp = [0x42, 0x4D]; - let ico = [0x00, 0x00, 0x01, 0x00]; - let junk_format = [0x01, 0x02, 0x03, 0x04, 0x05]; - - assert!(detect_image_format(&gif1).is_ok()); - assert!(detect_image_format(&gif2).is_ok()); - assert!(detect_image_format(&jpeg).is_ok()); - assert!(detect_image_format(&png).is_ok()); - assert!(detect_image_format(&webp).is_ok()); - assert!(detect_image_format(&bmp).is_ok()); - assert!(detect_image_format(&ico).is_ok()); - assert!(detect_image_format(&junk_format).is_err()); -} diff --git a/components/shared/script/Cargo.toml b/components/shared/script/Cargo.toml index f95a0ffdcc9..6b3a2384d41 100644 --- a/components/shared/script/Cargo.toml +++ b/components/shared/script/Cargo.toml @@ -44,4 +44,5 @@ uuid = { workspace = true } webdriver = { workspace = true } webgpu = { path = "../../webgpu" } webrender_api = { workspace = true } +webrender_traits = { workspace = true } webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] } diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 2f9822d2711..16f1e07710d 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -9,7 +9,6 @@ #![deny(missing_docs)] #![deny(unsafe_code)] -pub mod compositor; mod script_msg; pub mod serializable; pub mod transferable; @@ -29,14 +28,13 @@ use base::Epoch; use bitflags::bitflags; use bluetooth_traits::BluetoothRequest; use canvas_traits::webgl::WebGLPipeline; -use compositor::ScrollTreeNodeId; use crossbeam_channel::{RecvTimeoutError, Sender}; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; -use embedder_traits::{CompositorEventVariant, Cursor}; +use embedder_traits::CompositorEventVariant; use euclid::default::Point2D; use euclid::{Length, Rect, Scale, Size2D, UnknownUnit, Vector2D}; use http::{HeaderMap, Method}; -use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use ipc_channel::ipc::{IpcReceiver, IpcSender}; use ipc_channel::Error as IpcError; use keyboard_types::webdriver::Event as WebDriverInputEvent; use keyboard_types::{CompositionEvent, KeyboardEvent}; @@ -45,25 +43,21 @@ use log::warn; use malloc_size_of::malloc_size_of_is_0; use malloc_size_of_derive::MallocSizeOf; use media::WindowGLContext; -use net_traits::image::base::Image; use net_traits::image_cache::ImageCache; use net_traits::request::{Referrer, RequestBody}; use net_traits::storage_thread::StorageType; use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads}; -use pixels::PixelFormat; +use pixels::{Image, PixelFormat}; use profile_traits::{mem, time as profile_time}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use servo_atoms::Atom; use servo_url::{ImmutableOrigin, ServoUrl}; use style_traits::{CSSPixel, SpeculativePainter}; use webgpu::WebGPUMsg; -use webrender_api::units::{DeviceIntSize, DevicePixel, DevicePoint, LayoutPixel, LayoutPoint}; -use webrender_api::{ - BuiltDisplayList, BuiltDisplayListDescriptor, DocumentId, ExternalImageData, ExternalScrollId, - HitTestFlags, ImageData, ImageDescriptor, ImageKey, PipelineId as WebRenderPipelineId, -}; +use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel}; +use webrender_api::{DocumentId, ExternalScrollId, ImageKey}; +use webrender_traits::{UntrustedNodeAddress as WebRenderUntrustedNodeAddress, WebRenderScriptApi}; -use crate::compositor::CompositorDisplayListInfo; pub use crate::script_msg::{ DOMMessage, EventResult, HistoryEntryReplacement, IFrameSizeMsg, Job, JobError, JobResult, JobResultValue, JobType, LayoutMsg, LogEntry, SWManagerMsg, SWManagerSenders, ScopeThings, @@ -83,6 +77,12 @@ malloc_size_of_is_0!(UntrustedNodeAddress); #[allow(unsafe_code)] unsafe impl Send for UntrustedNodeAddress {} +impl From<WebRenderUntrustedNodeAddress> for UntrustedNodeAddress { + fn from(o: WebRenderUntrustedNodeAddress) -> Self { + UntrustedNodeAddress(o.0 as *const c_void) + } +} + impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress { fn from(o: style_traits::dom::OpaqueNode) -> Self { UntrustedNodeAddress(o.0 as *const c_void) @@ -691,7 +691,7 @@ pub struct InitialScriptState { /// 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: WebrenderIpcSender, + pub webrender_api_sender: WebRenderScriptApi, /// Application window's GL Context for Media player pub player_context: WindowGLContext, } @@ -1093,239 +1093,6 @@ impl From<i32> for MediaSessionActionType { } } -/// The result of a hit test in the compositor. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct CompositorHitTestResult { - /// The pipeline id of the resulting item. - pub pipeline_id: PipelineId, - - /// The hit test point in the item's viewport. - pub point_in_viewport: euclid::default::Point2D<f32>, - - /// The hit test point relative to the item itself. - pub point_relative_to_item: euclid::default::Point2D<f32>, - - /// The node address of the hit test result. - pub node: UntrustedNodeAddress, - - /// The cursor that should be used when hovering the item hit by the hit test. - pub cursor: Option<Cursor>, - - /// The scroll tree node associated with this hit test item. - pub scroll_tree_node: ScrollTreeNodeId, -} - -/// 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>), -} - -#[derive(Clone, Deserialize, Serialize)] -/// A mechanism to communicate with the parent process' WebRender instance. -pub struct WebrenderIpcSender(IpcSender<ScriptToCompositorMsg>); - -impl WebrenderIpcSender { - /// Create a new WebrenderIpcSender object that wraps the provided channel sender. - pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> Self { - Self(sender) - } - - /// 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); - } - }); - } -} - -#[derive(Deserialize, Serialize)] -/// Serializable image updates that must be performed by WebRender. -pub enum ImageUpdate { - /// Register a new image. - AddImage(ImageKey, ImageDescriptor, ImageData), - /// 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), -} - -#[derive(Debug, Deserialize, Serialize)] -/// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too -/// slow. -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(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 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)), - } - } -} - #[derive( Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize, )] diff --git a/components/shared/script/tests/compositor.rs b/components/shared/script/tests/compositor.rs index 289f4ffebf1..ee3fd72ad49 100644 --- a/components/shared/script/tests/compositor.rs +++ b/components/shared/script/tests/compositor.rs @@ -3,11 +3,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use euclid::Size2D; -use script_traits::compositor::{ - ScrollSensitivity, ScrollTree, ScrollTreeNodeId, ScrollableNodeInfo, -}; use webrender_api::units::LayoutVector2D; use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, SpatialId}; +use webrender_traits::display_list::{ + ScrollSensitivity, ScrollTree, ScrollTreeNodeId, ScrollableNodeInfo, +}; fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId { let pipeline_id = PipelineId(0, 0); diff --git a/components/shared/script_layout/Cargo.toml b/components/shared/script_layout/Cargo.toml index 57c4059b859..803a247bc2d 100644 --- a/components/shared/script_layout/Cargo.toml +++ b/components/shared/script_layout/Cargo.toml @@ -26,6 +26,7 @@ malloc_size_of = { workspace = true } malloc_size_of_derive = { workspace = true } metrics = { path = "../../metrics" } net_traits = { workspace = true } +pixels = { path = "../../pixels" } profile_traits = { workspace = true } range = { path = "../../range" } script_traits = { workspace = true } @@ -37,3 +38,4 @@ servo_url = { path = "../../url" } style = { workspace = true } style_traits = { workspace = true } webrender_api = { workspace = true } +webrender_traits = { workspace = true } diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 7c1f4ee2162..d07a009af0e 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -33,7 +33,7 @@ use profile_traits::mem::Report; use profile_traits::time; use script_traits::{ ConstellationControlMsg, InitialScriptState, LayoutControlMsg, LayoutMsg, LoadData, Painter, - ScrollState, UntrustedNodeAddress, WebrenderIpcSender, WindowSizeData, + ScrollState, UntrustedNodeAddress, WindowSizeData, }; use serde::{Deserialize, Serialize}; use servo_arc::Arc as ServoArc; @@ -51,6 +51,7 @@ use style::stylesheets::Stylesheet; use style::Atom; use style_traits::CSSPixel; use webrender_api::ImageKey; +use webrender_traits::WebRenderScriptApi; pub type GenericLayoutData = dyn Any + Send + Sync; @@ -165,7 +166,7 @@ pub struct LayoutConfig { pub image_cache: Arc<dyn ImageCache>, pub font_cache_thread: FontCacheThread, pub time_profiler_chan: time::ProfilerChan, - pub webrender_api_sender: WebrenderIpcSender, + pub webrender_api_sender: WebRenderScriptApi, pub paint_time_metrics: PaintTimeMetrics, pub window_size: WindowSizeData, } diff --git a/components/shared/script_layout/wrapper_traits.rs b/components/shared/script_layout/wrapper_traits.rs index 0adb51be244..399c8bd3362 100644 --- a/components/shared/script_layout/wrapper_traits.rs +++ b/components/shared/script_layout/wrapper_traits.rs @@ -12,7 +12,7 @@ use atomic_refcell::AtomicRef; use base::id::{BrowsingContextId, PipelineId}; use gfx_traits::ByteIndex; use html5ever::{local_name, namespace_url, ns, LocalName, Namespace}; -use net_traits::image::base::{Image, ImageMetadata}; +use pixels::{Image, ImageMetadata}; use range::Range; use servo_arc::Arc; use servo_url::ServoUrl; diff --git a/components/shared/webrender/Cargo.toml b/components/shared/webrender/Cargo.toml index f078b96101d..158872b0494 100644 --- a/components/shared/webrender/Cargo.toml +++ b/components/shared/webrender/Cargo.toml @@ -11,5 +11,12 @@ name = "webrender_traits" path = "lib.rs" [dependencies] +base = { workspace = true } +crossbeam-channel = { workspace = true } +embedder_traits = { workspace = true } euclid = { workspace = true } +ipc-channel = { workspace = true } +log = { workspace = true } +libc = { workspace = true } webrender_api = { workspace = true } +serde = { workspace = true } diff --git a/components/shared/script/compositor.rs b/components/shared/webrender/display_list.rs index e66c3bf8227..e66c3bf8227 100644 --- a/components/shared/script/compositor.rs +++ b/components/shared/webrender/display_list.rs diff --git a/components/shared/webrender/lib.rs b/components/shared/webrender/lib.rs index 8af3a17b609..d4883d150e4 100644 --- a/components/shared/webrender/lib.rs +++ b/components/shared/webrender/lib.rs @@ -4,14 +4,26 @@ #![deny(unsafe_code)] +pub mod display_list; + 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; -use webrender_api::units::TexelRect; +use ipc_channel::ipc::{self, IpcBytesReceiver, IpcSender}; +use libc::c_void; +use log::warn; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use webrender_api::units::{DevicePoint, LayoutPoint, TexelRect}; use webrender_api::{ - ExternalImage, ExternalImageHandler, ExternalImageId, ExternalImageSource, FontInstanceFlags, - FontInstanceKey, FontKey, NativeFontHandle, + BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData, + ExternalImageHandler, ExternalImageId, ExternalImageSource, ExternalScrollId, + FontInstanceFlags, FontInstanceKey, FontKey, HitTestFlags, ImageData, ImageDescriptor, + ImageKey, NativeFontHandle, PipelineId as WebRenderPipelineId, }; /// This trait is used as a bridge between the different GL clients @@ -178,3 +190,309 @@ pub trait WebRenderFontApi { fn add_font(&self, data: Arc<Vec<u8>>, index: u32) -> FontKey; fn add_system_font(&self, handle: NativeFontHandle) -> FontKey; } + +pub enum CanvasToCompositorMsg { + GenerateKey(Sender<ImageKey>), + UpdateImages(Vec<ImageUpdate>), +} + +pub enum FontToCompositorMsg { + AddFontInstance(FontKey, f32, FontInstanceFlags, Sender<FontInstanceKey>), + AddFont(Sender<FontKey>, u32, IpcBytesReceiver), + AddSystemFont(Sender<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>), +} + +/// 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 WebrenderIpcSender object that wraps the provided channel sender. + pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> Self { + Self(sender) + } + + /// 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); + } + }); + } +} + +#[derive(Deserialize, Serialize)] +/// Serializable image updates that must be performed by WebRender. +pub enum ImageUpdate { + /// Register a new image. + AddImage(ImageKey, ImageDescriptor, ImageData), + /// 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), +} + +#[derive(Debug, Deserialize, Serialize)] +/// Serialized `ImageData`. It contains IPC byte channel receiver to prevent from loading bytes too +/// slow. +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(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 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)), + } + } +} + +/// The address of a node. Layout sends these back. They must be validated via +/// `from_untrusted_node_address` before they can be used, because we do not trust layout. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct UntrustedNodeAddress(pub *const c_void); + +#[allow(unsafe_code)] +unsafe impl Send for UntrustedNodeAddress {} + +impl Serialize for UntrustedNodeAddress { + fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> { + (self.0 as usize).serialize(s) + } +} + +impl<'de> Deserialize<'de> for UntrustedNodeAddress { + fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> { + let value: usize = Deserialize::deserialize(d)?; + Ok(UntrustedNodeAddress::from_id(value)) + } +} + +impl UntrustedNodeAddress { + /// Creates an `UntrustedNodeAddress` from the given pointer address value. + #[inline] + pub fn from_id(id: usize) -> UntrustedNodeAddress { + UntrustedNodeAddress(id as *const c_void) + } +} + +/// The result of a hit test in the compositor. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct CompositorHitTestResult { + /// The pipeline id of the resulting item. + pub pipeline_id: PipelineId, + + /// The hit test point in the item's viewport. + pub point_in_viewport: euclid::default::Point2D<f32>, + + /// The hit test point relative to the item itself. + pub point_relative_to_item: euclid::default::Point2D<f32>, + + /// The node address of the hit test result. + pub node: UntrustedNodeAddress, + + /// The cursor that should be used when hovering the item hit by the hit test. + pub cursor: Option<Cursor>, + + /// The scroll tree node associated with this hit test item. + pub scroll_tree_node: ScrollTreeNodeId, +} |