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>
This commit is contained in:
Mukilan Thiyagarajan 2024-05-20 16:05:18 +05:30 committed by GitHub
parent c2076580f3
commit 2af6fe0b30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 666 additions and 617 deletions

28
Cargo.lock generated
View file

@ -879,6 +879,7 @@ dependencies = [
"toml 0.5.11",
"webrender",
"webrender_api",
"webrender_traits",
"webxr",
]
@ -887,7 +888,6 @@ name = "compositing_traits"
version = "0.0.1"
dependencies = [
"base",
"canvas",
"crossbeam-channel",
"embedder_traits",
"euclid",
@ -895,11 +895,12 @@ dependencies = [
"ipc-channel",
"keyboard-types",
"log",
"net_traits",
"pixels",
"script_traits",
"servo_url",
"style_traits",
"webrender_api",
"webrender_traits",
]
[[package]]
@ -3239,6 +3240,7 @@ dependencies = [
"malloc_size_of_derive",
"net_traits",
"parking_lot",
"pixels",
"profile_traits",
"range",
"rayon",
@ -3258,6 +3260,7 @@ dependencies = [
"unicode-bidi",
"unicode-script",
"webrender_api",
"webrender_traits",
"xi-unicode",
]
@ -3284,6 +3287,7 @@ dependencies = [
"log",
"net_traits",
"parking_lot",
"pixels",
"quickcheck",
"range",
"rayon",
@ -3301,6 +3305,7 @@ dependencies = [
"unicode-segmentation",
"url",
"webrender_api",
"webrender_traits",
"xi-unicode",
]
@ -3342,6 +3347,7 @@ dependencies = [
"time 0.1.45",
"url",
"webrender_api",
"webrender_traits",
]
[[package]]
@ -3378,6 +3384,7 @@ dependencies = [
"style_traits",
"url",
"webrender_api",
"webrender_traits",
]
[[package]]
@ -4026,6 +4033,7 @@ dependencies = [
"uuid",
"webpki-roots",
"webrender_api",
"webrender_traits",
]
[[package]]
@ -4058,6 +4066,7 @@ dependencies = [
"url",
"uuid",
"webrender_api",
"webrender_traits",
]
[[package]]
@ -4527,9 +4536,13 @@ name = "pixels"
version = "0.0.1"
dependencies = [
"euclid",
"image",
"ipc-channel",
"log",
"malloc_size_of",
"malloc_size_of_derive",
"serde",
"webrender_api",
]
[[package]]
@ -5123,6 +5136,7 @@ dependencies = [
"webdriver",
"webgpu",
"webrender_api",
"webrender_traits",
"webxr-api",
"xml5ever",
]
@ -5146,6 +5160,7 @@ dependencies = [
"malloc_size_of_derive",
"metrics",
"net_traits",
"pixels",
"profile_traits",
"range",
"script_traits",
@ -5157,6 +5172,7 @@ dependencies = [
"style",
"style_traits",
"webrender_api",
"webrender_traits",
]
[[package]]
@ -5206,6 +5222,7 @@ dependencies = [
"webdriver",
"webgpu",
"webrender_api",
"webrender_traits",
"webxr-api",
]
@ -7186,7 +7203,14 @@ dependencies = [
name = "webrender_traits"
version = "0.0.1"
dependencies = [
"base",
"crossbeam-channel",
"embedder_traits",
"euclid",
"ipc-channel",
"libc",
"log",
"serde",
"webrender_api",
]

View file

@ -26,8 +26,9 @@ use style::values::computed::font;
use style_traits::values::ToCss;
use webrender_api::units::{DeviceIntSize, RectExt as RectExt_};
use webrender_api::{ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey};
use webrender_traits::ImageUpdate;
use crate::canvas_paint_thread::{AntialiasMode, ImageUpdate, WebrenderApi};
use crate::canvas_paint_thread::{AntialiasMode, WebrenderApi};
use crate::raqote_backend::Repetition;
/// The canvas data stores a state machine for the current status of
@ -1082,13 +1083,13 @@ impl<'a> CanvasData<'a> {
match self.image_key {
Some(image_key) => {
debug!("Updating image {:?}.", image_key);
updates.push(ImageUpdate::Update(image_key, descriptor, data));
updates.push(ImageUpdate::UpdateImage(image_key, descriptor, data));
},
None => {
let Some(key) = self.webrender_api.generate_key() else {
return;
};
updates.push(ImageUpdate::Add(key, descriptor, data));
updates.push(ImageUpdate::AddImage(key, descriptor, data));
self.image_key = Some(key);
debug!("New image {:?}.", self.image_key);
},
@ -1097,7 +1098,7 @@ impl<'a> CanvasData<'a> {
if let Some(image_key) =
mem::replace(&mut self.very_old_image_key, self.old_image_key.take())
{
updates.push(ImageUpdate::Delete(image_key));
updates.push(ImageUpdate::DeleteImage(image_key));
}
self.webrender_api.update_images(updates);
@ -1215,10 +1216,10 @@ impl<'a> Drop for CanvasData<'a> {
fn drop(&mut self) {
let mut updates = vec![];
if let Some(image_key) = self.old_image_key.take() {
updates.push(ImageUpdate::Delete(image_key));
updates.push(ImageUpdate::DeleteImage(image_key));
}
if let Some(image_key) = self.very_old_image_key.take() {
updates.push(ImageUpdate::Delete(image_key));
updates.push(ImageUpdate::DeleteImage(image_key));
}
self.webrender_api.update_images(updates);

View file

@ -16,7 +16,8 @@ use gfx::font_context::FontContext;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use log::warn;
use webrender_api::{ImageData, ImageDescriptor, ImageKey};
use webrender_api::ImageKey;
use webrender_traits::ImageUpdate;
use crate::canvas_data::*;
@ -25,12 +26,6 @@ pub enum AntialiasMode {
None,
}
pub enum ImageUpdate {
Add(ImageKey, ImageDescriptor, ImageData),
Update(ImageKey, ImageDescriptor, ImageData),
Delete(ImageKey),
}
pub trait WebrenderApi {
/// Attempt to generate an [`ImageKey`], returning `None` in case of failure.
fn generate_key(&self) -> Option<ImageKey>;

View file

@ -43,6 +43,7 @@ style_traits = { workspace = true }
time = { workspace = true }
webrender = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }
webxr = { git = "https://github.com/servo/webxr" }
[build-dependencies]

View file

@ -13,10 +13,9 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use base::id::{PipelineId, TopLevelBrowsingContextId, WebViewId};
use base::{Epoch, WebRenderEpochToU16};
use canvas::canvas_paint_thread::ImageUpdate;
use compositing_traits::{
CanvasToCompositorMsg, CompositionPipeline, CompositorMsg, CompositorReceiver,
ConstellationMsg, FontToCompositorMsg, ForwardedToCompositorMsg, SendableFrameTree,
CompositionPipeline, CompositorMsg, CompositorReceiver, ConstellationMsg,
ForwardedToCompositorMsg, SendableFrameTree,
};
use crossbeam_channel::Sender;
use embedder_traits::Cursor;
@ -27,16 +26,13 @@ use image::{DynamicImage, ImageFormat};
use ipc_channel::ipc;
use libc::c_void;
use log::{debug, error, info, trace, warn};
use net_traits::image::base::Image;
use net_traits::image_cache::CorsStatus;
use pixels::PixelFormat;
use pixels::{CorsStatus, Image, PixelFormat};
use profile_traits::time::{self as profile_time, profile, ProfilerCategory};
use script_traits::compositor::{HitTestInfo, ScrollTree};
use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchEvent, WheelEvent};
use script_traits::{
AnimationState, AnimationTickType, CompositorHitTestResult, ConstellationControlMsg,
LayoutControlMsg, MouseButton, MouseEventType, ScrollState, TouchEventType, TouchId,
UntrustedNodeAddress, WheelDelta, WindowSizeData, WindowSizeType,
AnimationState, AnimationTickType, ConstellationControlMsg, LayoutControlMsg, MouseButton,
MouseEventType, ScrollState, TouchEventType, TouchId, WheelDelta, WindowSizeData,
WindowSizeType,
};
use servo_geometry::{DeviceIndependentPixel, FramebufferUintLength};
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
@ -51,6 +47,11 @@ use webrender_api::{
PropertyBinding, ReferenceFrameKind, RenderReasons, SampledScrollOffset, ScrollLocation,
SpaceAndClipInfo, SpatialId, SpatialTreeItemKey, TransformStyle,
};
use webrender_traits::display_list::{HitTestInfo, ScrollTree};
use webrender_traits::{
CanvasToCompositorMsg, CompositorHitTestResult, FontToCompositorMsg, ImageUpdate,
NetToCompositorMsg, ScriptToCompositorMsg, SerializedImageUpdate, UntrustedNodeAddress,
};
use crate::gl::RenderTargetInfo;
use crate::touch::{TouchAction, TouchHandler};
@ -695,9 +696,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
/// instance in the parent process.
fn handle_webrender_message(&mut self, msg: ForwardedToCompositorMsg) {
match msg {
ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::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);
@ -705,13 +706,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::SendScrollNode(
pipeline_id,
point,
external_scroll_id,
),
) => {
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,
@ -743,13 +742,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::SendDisplayList {
display_list_info,
display_list_descriptor,
display_list_receiver,
},
) => {
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,
@ -799,7 +796,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, transaction);
},
ForwardedToCompositorMsg::Layout(script_traits::ScriptToCompositorMsg::HitTest(
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::HitTest(
pipeline,
point,
flags,
@ -821,31 +818,23 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
let _ = sender.send(result);
},
ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::GenerateImageKey(sender),
) |
ForwardedToCompositorMsg::Net(net_traits::NetToCompositorMsg::GenerateImageKey(
sender,
)) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::GenerateImageKey(sender)) |
ForwardedToCompositorMsg::Net(NetToCompositorMsg::GenerateImageKey(sender)) => {
let _ = sender.send(self.webrender_api.generate_image_key());
},
ForwardedToCompositorMsg::Layout(
script_traits::ScriptToCompositorMsg::UpdateImages(updates),
) => {
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::UpdateImages(updates)) => {
let mut txn = Transaction::new();
for update in updates {
match update {
script_traits::SerializedImageUpdate::AddImage(key, desc, data) => {
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),
}
},
script_traits::SerializedImageUpdate::DeleteImage(key) => {
txn.delete_image(key)
},
script_traits::SerializedImageUpdate::UpdateImage(key, desc, data) => {
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),
@ -857,11 +846,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
ForwardedToCompositorMsg::Net(net_traits::NetToCompositorMsg::AddImage(
key,
desc,
data,
)) => {
ForwardedToCompositorMsg::Net(NetToCompositorMsg::AddImage(key, desc, data)) => {
let mut txn = Transaction::new();
txn.add_image(key, desc, data, None);
self.webrender_api
@ -929,13 +914,13 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
let mut txn = Transaction::new();
for update in updates {
match update {
ImageUpdate::Add(key, descriptor, data) => {
ImageUpdate::AddImage(key, descriptor, data) => {
txn.add_image(key, descriptor, data, None)
},
ImageUpdate::Update(key, descriptor, data) => {
ImageUpdate::UpdateImage(key, descriptor, data) => {
txn.update_image(key, descriptor, data, &DirtyRect::All)
},
ImageUpdate::Delete(key) => txn.delete_image(key),
ImageUpdate::DeleteImage(key) => txn.delete_image(key),
}
}
self.webrender_api
@ -1469,7 +1454,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
event_type,
button,
result.point_in_viewport.to_untyped(),
Some(result.node),
Some(result.node.into()),
Some(result.point_relative_to_item),
button as u16,
);
@ -1549,7 +1534,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
None => return,
};
let event = MouseMoveEvent(result.point_in_viewport, Some(result.node), 0);
let event = MouseMoveEvent(result.point_in_viewport, Some(result.node.into()), 0);
let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event);
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e);
@ -1568,7 +1553,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
event_type,
identifier,
result.point_in_viewport,
Some(result.node),
Some(result.node.into()),
);
let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event);
if let Err(e) = self.constellation_chan.send(msg) {
@ -1579,7 +1564,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
pub fn send_wheel_event(&mut self, delta: WheelDelta, point: DevicePoint) {
if let Some(result) = self.hit_test_at_point(point) {
let event = WheelEvent(delta, result.point_in_viewport, Some(result.node));
let event = WheelEvent(delta, result.point_in_viewport, Some(result.node.into()));
let msg = ConstellationMsg::ForwardEvent(result.pipeline_id, event);
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending event to constellation failed ({:?}).", e);

View file

@ -155,7 +155,7 @@ use style_traits::CSSPixel;
use webgpu::{self, WebGPU, WebGPURequest};
use webrender::{RenderApi, RenderApiSender};
use webrender_api::DocumentId;
use webrender_traits::WebrenderExternalImageRegistry;
use webrender_traits::{WebRenderNetApi, WebRenderScriptApi, WebrenderExternalImageRegistry};
use crate::browsingcontext::{
AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator,
@ -392,11 +392,11 @@ pub struct Constellation<STF, SWF> {
/// A channel for content processes to send messages that will
/// be relayed to the WebRender thread.
webrender_api_ipc_sender: script_traits::WebrenderIpcSender,
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: net_traits::WebrenderIpcSender,
webrender_image_api_sender: WebRenderNetApi,
/// A map of message-port Id to info.
message_ports: HashMap<MessagePortId, MessagePortInfo>,
@ -785,12 +785,8 @@ where
scheduler_receiver,
document_states: HashMap::new(),
webrender_document: state.webrender_document,
webrender_api_ipc_sender: script_traits::WebrenderIpcSender::new(
webrender_ipc_sender,
),
webrender_image_api_sender: net_traits::WebrenderIpcSender::new(
webrender_image_ipc_sender,
),
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(),

View file

@ -185,10 +185,10 @@ pub struct InitialPipelineState {
pub prev_throttled: bool,
/// Webrender api.
pub webrender_image_api_sender: net_traits::WebrenderIpcSender,
pub webrender_image_api_sender: webrender_traits::WebRenderNetApi,
/// Webrender api.
pub webrender_api_sender: script_traits::WebrenderIpcSender,
pub webrender_api_sender: webrender_traits::WebRenderScriptApi,
/// The ID of the document processed by this script thread.
pub webrender_document: DocumentId,
@ -502,8 +502,8 @@ pub struct UnprivilegedPipelineContent {
opts: Opts,
prefs: HashMap<String, PrefValue>,
pipeline_namespace_id: PipelineNamespaceId,
webrender_api_sender: script_traits::WebrenderIpcSender,
webrender_image_api_sender: net_traits::WebrenderIpcSender,
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,

View file

@ -30,6 +30,7 @@ log = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
net_traits = { workspace = true }
pixels = { path = "../pixels" }
parking_lot = { workspace = true }
profile_traits = { workspace = true }
range = { path = "../range" }
@ -50,4 +51,5 @@ style_traits = { workspace = true }
unicode-bidi = { workspace = true, features = ["with_serde"] }
unicode-script = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }
xi-unicode = { workspace = true }

View file

@ -27,7 +27,6 @@ use log::{debug, warn};
use net_traits::image_cache::UsePlaceholder;
use range::Range;
use script_layout_interface::{combine_id_with_fragment_type, FragmentType};
use script_traits::compositor::ScrollSensitivity;
use servo_config::opts;
use servo_geometry::{self, MaxRect};
use style::color::AbsoluteColor;
@ -52,6 +51,7 @@ use webrender_api::{
ExternalScrollId, FilterOp, GlyphInstance, ImageRendering, LineStyle, NinePatchBorder,
NinePatchBorderSource, NormalBorder, PropertyBinding, StickyOffsetBounds,
};
use webrender_traits::display_list::ScrollSensitivity;
use super::StackingContextId;
use crate::block::BlockFlow;

View file

@ -20,8 +20,7 @@ use base::id::PipelineId;
use base::print_tree::PrintTree;
use embedder_traits::Cursor;
use euclid::{SideOffsets2D, Vector2D};
use net_traits::image::base::Image;
use script_traits::compositor::{ScrollSensitivity, ScrollTreeNodeId};
use pixels::Image;
use serde::Serialize;
use servo_geometry::MaxRect;
use style::computed_values::_servo_top_layer::T as InTopLayer;
@ -33,6 +32,7 @@ use webrender_api::{
FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags, Shadow,
SpatialId, StickyOffsetBounds, TransformStyle,
};
use webrender_traits::display_list::{ScrollSensitivity, ScrollTreeNodeId};
use super::StackingContextId;

View file

@ -10,15 +10,15 @@
use base::id::PipelineId;
use base::WebRenderEpochToU16;
use log::trace;
use script_traits::compositor::{
CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo,
};
use webrender_api::units::{LayoutPoint, LayoutSize, LayoutVector2D};
use webrender_api::{
self, ClipChainId, ClipId, CommonItemProperties, DisplayItem as WrDisplayItem,
DisplayListBuilder, Epoch, HasScrollLinkedEffect, PrimitiveFlags, PropertyBinding, RasterSpace,
ReferenceFrameKind, SpaceAndClipInfo, SpatialId, SpatialTreeItemKey,
};
use webrender_traits::display_list::{
CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo,
};
use crate::display_list::items::{
BaseDisplayItem, ClipScrollNode, ClipScrollNodeType, ClipType, DisplayItem, DisplayList,

View file

@ -20,8 +20,8 @@ use gfx::text::text_run::{TextRun, TextRunSlice};
use html5ever::{local_name, namespace_url, ns};
use ipc_channel::ipc::IpcSender;
use log::debug;
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use pixels::{Image, ImageMetadata};
use range::*;
use script_layout_interface::wrapper_traits::{
PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode,

View file

@ -30,6 +30,7 @@ ipc-channel = { workspace = true }
log = { workspace = true }
net_traits = { workspace = true }
parking_lot = { workspace = true }
pixels = { path = "../pixels" }
range = { path = "../range" }
rayon = { workspace = true }
script_layout_interface = { workspace = true }
@ -47,6 +48,7 @@ unicode-segmentation = { workspace = true }
url = { workspace = true }
data-url = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }
xi-unicode = { workspace = true }
[dev-dependencies]

View file

@ -12,7 +12,6 @@ use euclid::{Point2D, SideOffsets2D, Size2D};
use fnv::FnvHashMap;
use gfx::text::glyph::GlyphStore;
use net_traits::image_cache::UsePlaceholder;
use script_traits::compositor::{CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId};
use servo_geometry::MaxRect;
use style::color::{AbsoluteColor, ColorSpace};
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
@ -24,6 +23,9 @@ use style::values::specified::text::TextDecorationLine;
use style::values::specified::ui::CursorKind;
use style_traits::CSSPixel;
use webrender_api::{self as wr, units, BoxShadowClipMode, ClipChainId};
use webrender_traits::display_list::{
CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId,
};
use wr::units::LayoutVector2D;
use crate::context::LayoutContext;

View file

@ -9,7 +9,6 @@ use base::print_tree::PrintTree;
use euclid::default::Rect;
use euclid::SideOffsets2D;
use log::warn;
use script_traits::compositor::{ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo};
use servo_arc::Arc as ServoArc;
use servo_config::opts::DebugOptions;
use style::computed_values::float::T as ComputedFloat;
@ -24,6 +23,7 @@ use style::values::specified::box_::DisplayOutside;
use style::Zero;
use webrender_api as wr;
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
use webrender_traits::display_list::{ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo};
use wr::units::{LayoutPixel, LayoutSize};
use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};

View file

@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use base::id::{BrowsingContextId, PipelineId};
use html5ever::{local_name, namespace_url, ns};
use net_traits::image::base::Image as NetImage;
use pixels::Image;
use script_layout_interface::wrapper_traits::{
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
@ -96,7 +96,7 @@ impl Drop for BoxSlot<'_> {
pub(crate) trait NodeExt<'dom>: 'dom + LayoutNode<'dom> {
/// Returns the image if its loaded, and its size in image pixels
/// adjusted for `image_density`.
fn as_image(self) -> Option<(Option<Arc<NetImage>>, PhysicalSize<f64>)>;
fn as_image(self) -> Option<(Option<Arc<Image>>, PhysicalSize<f64>)>;
fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
fn as_iframe(self) -> Option<(PipelineId, BrowsingContextId)>;
fn as_video(self) -> Option<(webrender_api::ImageKey, PhysicalSize<f64>)>;
@ -117,7 +117,7 @@ impl<'dom, LayoutNodeType> NodeExt<'dom> for LayoutNodeType
where
LayoutNodeType: 'dom + LayoutNode<'dom>,
{
fn as_image(self) -> Option<(Option<Arc<NetImage>>, PhysicalSize<f64>)> {
fn as_image(self) -> Option<(Option<Arc<Image>>, PhysicalSize<f64>)> {
let node = self.to_threadsafe();
let (resource, metadata) = node.image_data()?;
let (width, height) = resource

View file

@ -7,13 +7,13 @@ use script_layout_interface::wrapper_traits::{
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
use script_layout_interface::{LayoutElementType, LayoutNodeType};
use script_traits::compositor::ScrollSensitivity;
use serde::Serialize;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{Length, Overflow};
use style_traits::CSSPixel;
use webrender_traits::display_list::ScrollSensitivity;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;

View file

@ -6,12 +6,12 @@ use app_units::Au;
use base::print_tree::PrintTree;
use euclid::default::{Point2D, Rect, Size2D};
use fxhash::FxHashSet;
use script_traits::compositor::ScrollSensitivity;
use serde::Serialize;
use style::animation::AnimationSetKey;
use style::dom::OpaqueNode;
use style::values::computed::Length;
use webrender_api::units;
use webrender_traits::display_list::ScrollSensitivity;
use super::{ContainingBlockManager, Fragment, Tag};
use crate::cell::ArcRefCell;

View file

@ -10,8 +10,8 @@ use base::id::{BrowsingContextId, PipelineId};
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
use data_url::DataUrl;
use ipc_channel::ipc::{self, IpcSender};
use net_traits::image::base::Image;
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use pixels::Image;
use serde::Serialize;
use servo_arc::Arc as ServoArc;
use style::properties::ComputedValues;

View file

@ -45,3 +45,4 @@ style_traits = { workspace = true }
time = { workspace = true }
url = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }

View file

@ -69,7 +69,7 @@ use script_layout_interface::{
use script_traits::{
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg,
LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress,
WebrenderIpcSender, WindowSizeData, WindowSizeType,
WindowSizeData, WindowSizeType,
};
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom;
@ -102,6 +102,7 @@ use style::traversal_flags::TraversalFlags;
use style_traits::{CSSPixel, DevicePixel, SpeculativePainter};
use url::Url;
use webrender_api::{units, ColorF, HitTestFlags};
use webrender_traits::WebRenderScriptApi;
/// Information needed by layout.
pub struct LayoutThread {
@ -176,7 +177,7 @@ pub struct LayoutThread {
registered_painters: RegisteredPaintersImpl,
/// Webrender interface.
webrender_api: WebrenderIpcSender,
webrender_api: WebRenderScriptApi,
/// Paint time metrics.
paint_time_metrics: PaintTimeMetrics,
@ -365,7 +366,7 @@ impl Layout for LayoutThread {
.webrender_api
.hit_test(Some(self.id.into()), client_point, flags);
results.iter().map(|result| result.node).collect()
results.iter().map(|result| result.node.into()).collect()
}
fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse {
@ -567,7 +568,7 @@ impl LayoutThread {
image_cache: Arc<dyn ImageCache>,
font_cache_thread: FontCacheThread,
time_profiler_chan: profile_time::ProfilerChan,
webrender_api: WebrenderIpcSender,
webrender_api: WebRenderScriptApi,
paint_time_metrics: PaintTimeMetrics,
window_size: WindowSizeData,
) -> LayoutThread {

View file

@ -41,3 +41,4 @@ style = { workspace = true }
style_traits = { workspace = true }
url = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }

View file

@ -55,7 +55,7 @@ use script_layout_interface::{
use script_traits::{
ConstellationControlMsg, DrawAPaintImageResult, IFrameSizeMsg, LayoutControlMsg,
LayoutMsg as ConstellationMsg, PaintWorkletError, Painter, ScrollState, UntrustedNodeAddress,
WebrenderIpcSender, WindowSizeData, WindowSizeType,
WindowSizeData, WindowSizeType,
};
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom;
@ -89,6 +89,7 @@ use style_traits::{CSSPixel, DevicePixel, SpeculativePainter};
use url::Url;
use webrender_api::units::LayoutPixel;
use webrender_api::{units, ExternalScrollId, HitTestFlags};
use webrender_traits::WebRenderScriptApi;
/// Information needed by layout.
pub struct LayoutThread {
@ -158,7 +159,7 @@ pub struct LayoutThread {
registered_painters: RegisteredPaintersImpl,
/// Webrender interface.
webrender_api: WebrenderIpcSender,
webrender_api: WebRenderScriptApi,
/// Paint time metrics.
paint_time_metrics: PaintTimeMetrics,
@ -328,7 +329,7 @@ impl Layout for LayoutThread {
.webrender_api
.hit_test(Some(self.id.into()), client_point, flags);
results.iter().map(|result| result.node).collect()
results.iter().map(|result| result.node.into()).collect()
}
fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse {
@ -484,7 +485,7 @@ impl LayoutThread {
image_cache: Arc<dyn ImageCache>,
font_cache_thread: FontCacheThread,
time_profiler_chan: profile_time::ProfilerChan,
webrender_api_sender: WebrenderIpcSender,
webrender_api_sender: WebRenderScriptApi,
paint_time_metrics: PaintTimeMetrics,
window_size: WindowSizeData,
) -> LayoutThread {

View file

@ -65,6 +65,7 @@ tungstenite = { workspace = true }
url = { workspace = true }
uuid = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }
webpki-roots = { workspace = true }
[dev-dependencies]

View file

@ -12,19 +12,17 @@ use embedder_traits::resources::{self, Resource};
use imsz::imsz_from_reader;
use ipc_channel::ipc::IpcSender;
use log::{debug, warn};
use net_traits::image::base::{load_from_memory, Image, ImageMetadata};
use net_traits::image_cache::{
CorsStatus, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponder,
ImageResponse, PendingImageId, PendingImageResponse, UsePlaceholder,
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponder, ImageResponse,
PendingImageId, PendingImageResponse, UsePlaceholder,
};
use net_traits::request::CorsSettings;
use net_traits::{
FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError, WebrenderIpcSender,
};
use pixels::PixelFormat;
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::{ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat};
use webrender_traits::WebRenderNetApi;
use crate::resource_thread::CoreResourceThreadPool;
@ -47,13 +45,13 @@ fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg
DecoderMsg { key, image }
}
fn get_placeholder_image(webrender_api: &WebrenderIpcSender, 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(webrender_api, &mut image);
Arc::new(image)
}
fn set_webrender_image_key(webrender_api: &WebrenderIpcSender, image: &mut Image) {
fn set_webrender_image_key(webrender_api: &WebRenderNetApi, image: &mut Image) {
if image.id.is_some() {
return;
}
@ -331,7 +329,7 @@ struct ImageCacheStore {
placeholder_url: ServoUrl,
// Webrender API instance.
webrender_api: WebrenderIpcSender,
webrender_api: WebRenderNetApi,
}
impl ImageCacheStore {
@ -418,7 +416,7 @@ pub struct ImageCacheImpl {
}
impl ImageCache for ImageCacheImpl {
fn new(webrender_api: WebrenderIpcSender) -> ImageCacheImpl {
fn new(webrender_api: WebRenderNetApi) -> ImageCacheImpl {
debug!("New image cache");
let rippy_data = resources::read_bytes(Resource::RippyPNG);

View file

@ -12,6 +12,10 @@ path = "lib.rs"
[dependencies]
euclid = { workspace = true }
ipc-channel = { workspace = true }
image = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
log = { workspace = true }
serde = { workspace = true, features = ["derive"] }
webrender_api = { workspace = true }

View file

@ -3,10 +3,15 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::borrow::Cow;
use std::fmt;
use euclid::default::{Point2D, Rect, Size2D};
use image::ImageFormat;
use ipc_channel::ipc::IpcSharedMemory;
use log::debug;
use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Serialize};
use webrender_api::ImageKey;
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum PixelFormat {
@ -98,3 +103,148 @@ pub fn clip(
.intersection(&Rect::from_size(surface))
.filter(|rect| !rect.is_empty())
}
/// 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,
}
#[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();
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"
}
#[cfg(test)]
mod test {
use super::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());
}
}

View file

@ -116,6 +116,7 @@ uuid = { workspace = true, features = ["serde"] }
webdriver = { workspace = true }
webgpu = { path = "../webgpu" }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }
webxr-api = { git = "https://github.com/servo/webxr", features = ["ipc"] }
xml5ever = { workspace = true }

View file

@ -20,10 +20,9 @@ use ipc_channel::router::ROUTER;
use js::jsapi::JSAutoRealm;
use js::rust::HandleObject;
use mime::{self, Mime};
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache::{
CorsStatus, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponse,
PendingImageId, PendingImageResponse, UsePlaceholder,
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponse, PendingImageId,
PendingImageResponse, UsePlaceholder,
};
use net_traits::request::{CorsSettings, Destination, Initiator, Referrer, RequestBuilder};
use net_traits::{
@ -31,6 +30,7 @@ use net_traits::{
ResourceFetchTiming, ResourceTimingType,
};
use num_traits::ToPrimitive;
use pixels::{CorsStatus, Image, ImageMetadata};
use servo_url::origin::{ImmutableOrigin, MutableOrigin};
use servo_url::ServoUrl;
use style::attr::{

View file

@ -20,14 +20,13 @@ use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use js::jsapi::JSAutoRealm;
use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward, WindowGLContext};
use net_traits::image::base::Image;
use net_traits::request::Destination;
use net_traits::{
CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata, NetworkError,
ResourceFetchTiming, ResourceTimingType,
};
use pixels::Image;
use script_layout_interface::HTMLMediaData;
use script_traits::{ImageUpdate, WebrenderIpcSender};
use servo_config::pref;
use servo_media::player::audio::AudioRenderer;
use servo_media::player::video::{VideoFrame, VideoFrameRenderer};
@ -38,6 +37,7 @@ use webrender_api::{
ExternalImageData, ExternalImageId, ExternalImageType, ImageBufferKind, ImageData,
ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
};
use webrender_traits::{ImageUpdate, WebRenderScriptApi};
use crate::document_loader::{LoadBlocker, LoadType};
use crate::dom::attr::Attr;
@ -154,7 +154,7 @@ impl FrameHolder {
pub struct MediaFrameRenderer {
player_id: Option<u64>,
api: WebrenderIpcSender,
api: WebRenderScriptApi,
current_frame: Option<(ImageKey, i32, i32)>,
old_frame: Option<ImageKey>,
very_old_frame: Option<ImageKey>,
@ -163,7 +163,7 @@ pub struct MediaFrameRenderer {
}
impl MediaFrameRenderer {
fn new(render_api_sender: WebrenderIpcSender) -> Self {
fn new(render_api_sender: WebRenderScriptApi) -> Self {
Self {
player_id: None,
api: render_api_sender,

View file

@ -7,7 +7,7 @@ use std::default::Default;
use dom_struct::dom_struct;
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
use js::rust::HandleObject;
use net_traits::image::base::Image;
use pixels::Image;
use servo_arc::Arc;
use crate::dom::attr::Attr;

View file

@ -23,7 +23,7 @@ use js::jsapi::JSObject;
use js::rust::HandleObject;
use libc::{self, c_void, uintptr_t};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use net_traits::image::base::{Image, ImageMetadata};
use pixels::{Image, ImageMetadata};
use script_layout_interface::{
GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType, QueryMsg,
SVGSVGData, StyleData, TrustedNodeAddress,

View file

@ -56,7 +56,7 @@ use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use script_traits::{
ConstellationControlMsg, DocumentState, HistoryEntryReplacement, LoadData, ScriptMsg,
ScriptToConstellationChan, ScrollState, StructuredSerializedData, TimerEventId,
TimerSchedulerMsg, WebrenderIpcSender, WindowSizeData, WindowSizeType,
TimerSchedulerMsg, WindowSizeData, WindowSizeType,
};
use selectors::attr::CaseSensitivity;
use servo_arc::Arc as ServoArc;
@ -76,6 +76,7 @@ use style_traits::{CSSPixel, DevicePixel, ParsingMode};
use url::Position;
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel};
use webrender_api::{DocumentId, ExternalScrollId};
use webrender_traits::WebRenderScriptApi;
use super::bindings::trace::HashMapTracedValues;
use crate::dom::bindings::cell::{DomRefCell, Ref};
@ -318,7 +319,7 @@ pub struct Window {
/// Webrender API Sender
#[ignore_malloc_size_of = "Wraps an IpcSender"]
#[no_trace]
webrender_api_sender: WebrenderIpcSender,
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.
@ -521,7 +522,7 @@ impl Window {
self.add_pending_reflow();
}
pub fn get_webrender_api_sender(&self) -> WebrenderIpcSender {
pub fn get_webrender_api_sender(&self) -> WebRenderScriptApi {
self.webrender_api_sender.clone()
}
@ -2537,7 +2538,7 @@ impl Window {
webxr_registry: webxr_api::Registry,
microtask_queue: Rc<MicrotaskQueue>,
webrender_document: DocumentId,
webrender_api_sender: WebrenderIpcSender,
webrender_api_sender: WebRenderScriptApi,
relayout_event: bool,
prepare_for_screenshot: bool,
unminify_js: bool,

View file

@ -11,7 +11,7 @@ use std::sync::Arc as StdArc;
use base::id::{BrowsingContextId, PipelineId};
use gfx_traits::ByteIndex;
use html5ever::{local_name, namespace_url, ns};
use net_traits::image::base::{Image, ImageMetadata};
use pixels::{Image, ImageMetadata};
use range::Range;
use script_layout_interface::wrapper_traits::{
LayoutDataTrait, LayoutNode, PseudoElementType, ThreadSafeLayoutNode,

View file

@ -83,7 +83,7 @@ use script_traits::{
LayoutMsg, LoadData, LoadOrigin, MediaSessionActionType, MouseButton, MouseEventType,
NewLayoutInfo, Painter, ProgressiveWebMetricType, ScriptMsg, ScriptToConstellationChan,
StructuredSerializedData, TimerSchedulerMsg, TouchEventType, TouchId, UntrustedNodeAddress,
UpdatePipelineIdReason, WebrenderIpcSender, WheelDelta, WindowSizeData, WindowSizeType,
UpdatePipelineIdReason, WheelDelta, WindowSizeData, WindowSizeType,
};
use servo_atoms::Atom;
use servo_config::opts;
@ -95,6 +95,7 @@ use url::Position;
use webgpu::WebGPUMsg;
use webrender_api::units::LayoutPixel;
use webrender_api::DocumentId;
use webrender_traits::WebRenderScriptApi;
use crate::document_loader::DocumentLoader;
use crate::dom::bindings::cell::DomRefCell;
@ -674,7 +675,7 @@ pub struct ScriptThread {
/// Webrender API sender.
#[no_trace]
webrender_api_sender: WebrenderIpcSender,
webrender_api_sender: WebRenderScriptApi,
/// Periodically print out on which events script threads spend their processing time.
profile_script_events: bool,

View file

@ -36,8 +36,7 @@ use compositing::webview::UnknownWebView;
use compositing::windowing::{EmbedderEvent, EmbedderMethods, WindowMethods};
use compositing::{CompositeTarget, IOCompositor, InitialCompositorState, ShutdownState};
use compositing_traits::{
CanvasToCompositorMsg, CompositorMsg, CompositorProxy, CompositorReceiver, ConstellationMsg,
FontToCompositorMsg, ForwardedToCompositorMsg,
CompositorMsg, CompositorProxy, CompositorReceiver, ConstellationMsg, ForwardedToCompositorMsg,
};
#[cfg(all(
not(target_os = "windows"),
@ -96,8 +95,8 @@ use webrender_api::{
NativeFontHandle,
};
use webrender_traits::{
WebRenderFontApi, WebrenderExternalImageHandlers, WebrenderExternalImageRegistry,
WebrenderImageHandlerType,
CanvasToCompositorMsg, FontToCompositorMsg, ImageUpdate, WebRenderFontApi,
WebrenderExternalImageHandlers, WebrenderExternalImageRegistry, WebrenderImageHandlerType,
};
pub use {
background_hang_monitor, base, bluetooth, bluetooth_traits, canvas, canvas_traits, compositing,
@ -1100,7 +1099,7 @@ impl canvas_paint_thread::WebrenderApi for CanvasWebrenderApi {
)));
receiver.recv().ok()
}
fn update_images(&self, updates: Vec<canvas_paint_thread::ImageUpdate>) {
fn update_images(&self, updates: Vec<ImageUpdate>) {
self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas(
CanvasToCompositorMsg::UpdateImages(updates),

View file

@ -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 }

View file

@ -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),

View file

@ -39,3 +39,4 @@ servo_url = { path = "../../url" }
url = { workspace = true }
uuid = { workspace = true }
webrender_api = { workspace = true }
webrender_traits = { workspace = true }

View file

@ -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"
}

View file

@ -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,
}

View file

@ -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();
}

View file

@ -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());
}

View file

@ -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"] }

View file

@ -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,
)]

View file

@ -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);

View file

@ -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 }

View file

@ -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,
}

View file

@ -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;

View file

@ -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 }

View file

@ -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,
}

View file

@ -162,6 +162,7 @@ class MachCommands(CommandBase):
"constellation",
"style_config",
"compositing",
"pixels",
]
if not packages:
packages = set(os.listdir(path.join(self.context.topdir, "tests", "unit"))) - set(['.DS_Store'])