diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-01-30 09:10:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-30 08:10:13 +0000 |
commit | 7f0d0830e779f37da8aa7f7025edcebe57b2db26 (patch) | |
tree | e440baab928da40b4bba1a41a780b57d6953d998 /third_party/webrender/webrender_api/src | |
parent | 9b6c473695e14c1a37dd70325657519b901e7efc (diff) | |
download | servo-7f0d0830e779f37da8aa7f7025edcebe57b2db26.tar.gz servo-7f0d0830e779f37da8aa7f7025edcebe57b2db26.zip |
deps: Stop vendoring WebRender (#31212)
The new strategy for dependencies with upstream in Gecko is to manage
them in separate repositories, which will more easily allow rebasing our
changes on top of newer Gecko work.
Diffstat (limited to 'third_party/webrender/webrender_api/src')
-rw-r--r-- | third_party/webrender/webrender_api/src/channel.rs | 180 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/color.rs | 160 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/display_item.rs | 1738 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/display_item_cache.rs | 115 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/display_list.rs | 2057 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/font.rs | 605 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/gradient_builder.rs | 180 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/image.rs | 580 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/lib.rs | 665 | ||||
-rw-r--r-- | third_party/webrender/webrender_api/src/units.rs | 325 |
10 files changed, 0 insertions, 6605 deletions
diff --git a/third_party/webrender/webrender_api/src/channel.rs b/third_party/webrender/webrender_api/src/channel.rs deleted file mode 100644 index 7d21c6e4339..00000000000 --- a/third_party/webrender/webrender_api/src/channel.rs +++ /dev/null @@ -1,180 +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 http://mozilla.org/MPL/2.0/. */ - -use crate::{Epoch, PipelineId}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::io::{self, Cursor, Error, ErrorKind, Read}; -use std::mem; - -pub use crossbeam_channel as crossbeam; - -#[cfg(not(target_os = "windows"))] -pub use crossbeam_channel::{Sender, Receiver}; - -#[cfg(target_os = "windows")] -pub use std::sync::mpsc::{Sender, Receiver}; - -#[derive(Clone)] -pub struct Payload { - /// An epoch used to get the proper payload for a pipeline id frame request. - /// - /// TODO(emilio): Is this still relevant? We send the messages for the same - /// pipeline in order, so we shouldn't need it. Seems like this was only - /// wallpapering (in most cases) the underlying problem in #991. - pub epoch: Epoch, - /// A pipeline id to key the payload with, along with the epoch. - pub pipeline_id: PipelineId, - pub display_list_data: Vec<u8>, -} - -impl Payload { - /// Convert the payload to a raw byte vector, in order for it to be - /// efficiently shared via shmem, for example. - /// This is a helper static method working on a slice. - pub fn construct_data(epoch: Epoch, pipeline_id: PipelineId, dl_data: &[u8]) -> Vec<u8> { - let mut data = Vec::with_capacity( - mem::size_of::<u32>() + 2 * mem::size_of::<u32>() + mem::size_of::<u64>() + dl_data.len(), - ); - data.write_u32::<LittleEndian>(epoch.0).unwrap(); - data.write_u32::<LittleEndian>(pipeline_id.0).unwrap(); - data.write_u32::<LittleEndian>(pipeline_id.1).unwrap(); - data.write_u64::<LittleEndian>(dl_data.len() as u64) - .unwrap(); - data.extend_from_slice(dl_data); - data - } - /// Convert the payload to a raw byte vector, in order for it to be - /// efficiently shared via shmem, for example. - pub fn to_data(&self) -> Vec<u8> { - Self::construct_data(self.epoch, self.pipeline_id, &self.display_list_data) - } - - /// Deserializes the given payload from a raw byte vector. - pub fn from_data(data: &[u8]) -> Payload { - let mut payload_reader = Cursor::new(data); - let epoch = Epoch(payload_reader.read_u32::<LittleEndian>().unwrap()); - let pipeline_id = PipelineId( - payload_reader.read_u32::<LittleEndian>().unwrap(), - payload_reader.read_u32::<LittleEndian>().unwrap(), - ); - - let dl_size = payload_reader.read_u64::<LittleEndian>().unwrap() as usize; - let mut built_display_list_data = vec![0; dl_size]; - payload_reader - .read_exact(&mut built_display_list_data[..]) - .unwrap(); - - assert_eq!(payload_reader.position(), data.len() as u64); - - Payload { - epoch, - pipeline_id, - display_list_data: built_display_list_data, - } - } -} - -pub type PayloadSender = MsgSender<Payload>; - -pub type PayloadReceiver = MsgReceiver<Payload>; - -pub struct MsgReceiver<T> { - rx: Receiver<T>, -} - -impl<T> MsgReceiver<T> { - pub fn recv(&self) -> Result<T, Error> { - self.rx.recv().map_err(|e| io::Error::new(ErrorKind::Other, e.to_string())) - } - - pub fn to_crossbeam_receiver(self) -> Receiver<T> { - self.rx - } -} - -#[derive(Clone)] -pub struct MsgSender<T> { - tx: Sender<T>, -} - -impl<T> MsgSender<T> { - pub fn send(&self, data: T) -> Result<(), Error> { - self.tx.send(data).map_err(|_| Error::new(ErrorKind::Other, "cannot send on closed channel")) - } -} - -pub fn payload_channel() -> Result<(PayloadSender, PayloadReceiver), Error> { - let (tx, rx) = unbounded_channel(); - Ok((PayloadSender { tx }, PayloadReceiver { rx })) -} - -pub fn msg_channel<T>() -> Result<(MsgSender<T>, MsgReceiver<T>), Error> { - let (tx, rx) = unbounded_channel(); - Ok((MsgSender { tx }, MsgReceiver { rx })) -} - -/// -/// These serialize methods are needed to satisfy the compiler -/// which uses these implementations for the recording tool. -/// The recording tool only outputs messages that don't contain -/// Senders or Receivers, so in theory these should never be -/// called in the in-process config. If they are called, -/// there may be a bug in the messages that the replay tool is writing. -/// - -impl<T> Serialize for MsgSender<T> { - fn serialize<S: Serializer>(&self, _: S) -> Result<S::Ok, S::Error> { - unreachable!(); - } -} - -impl<'de, T> Deserialize<'de> for MsgSender<T> { - fn deserialize<D>(_: D) -> Result<MsgSender<T>, D::Error> - where D: Deserializer<'de> { - unreachable!(); - } -} - -/// A create a channel intended for one-shot uses, for example the channels -/// created to block on a synchronous query and then discarded, -#[cfg(not(target_os = "windows"))] -pub fn single_msg_channel<T>() -> (Sender<T>, Receiver<T>) { - crossbeam_channel::bounded(1) -} - -/// A fast MPMC message channel that can hold a fixed number of messages. -/// -/// If the channel is full, the sender will block upon sending extra messages -/// until the receiver has consumed some messages. -/// The capacity parameter should be chosen either: -/// - high enough to avoid blocking on the common cases, -/// - or, on the contrary, using the blocking behavior as a means to prevent -/// fast producers from building up work faster than it is consumed. -#[cfg(not(target_os = "windows"))] -pub fn fast_channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) { - crossbeam_channel::bounded(capacity) -} - -/// Creates an MPMC channel that is a bit slower than the fast_channel but doesn't -/// have a limit on the number of messages held at a given time and therefore -/// doesn't block when sending. -#[cfg(not(target_os = "windows"))] -pub use crossbeam_channel::unbounded as unbounded_channel; - - -#[cfg(target_os = "windows")] -pub fn fast_channel<T>(_cap: usize) -> (Sender<T>, Receiver<T>) { - std::sync::mpsc::channel() -} - -#[cfg(target_os = "windows")] -pub fn unbounded_channel<T>() -> (Sender<T>, Receiver<T>) { - std::sync::mpsc::channel() -} - -#[cfg(target_os = "windows")] -pub fn single_msg_channel<T>() -> (Sender<T>, Receiver<T>) { - std::sync::mpsc::channel() -} diff --git a/third_party/webrender/webrender_api/src/color.rs b/third_party/webrender/webrender_api/src/color.rs deleted file mode 100644 index f19f83bb3d0..00000000000 --- a/third_party/webrender/webrender_api/src/color.rs +++ /dev/null @@ -1,160 +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 http://mozilla.org/MPL/2.0/. */ - -use peek_poke::PeekPoke; -use std::cmp; -use std::hash::{Hash, Hasher}; - -/// Represents pre-multiplied RGBA colors with floating point numbers. -/// -/// All components must be between 0.0 and 1.0. -/// An alpha value of 1.0 is opaque while 0.0 is fully transparent. -/// -/// In premultiplied colors transitions to transparent always look "nice" -/// therefore they are used in CSS gradients. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)] -pub struct PremultipliedColorF { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} - -#[allow(missing_docs)] -impl PremultipliedColorF { - pub const BLACK: PremultipliedColorF = PremultipliedColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }; - pub const TRANSPARENT: PremultipliedColorF = PremultipliedColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }; - pub const WHITE: PremultipliedColorF = PremultipliedColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }; - - pub fn to_array(&self) -> [f32; 4] { - [self.r, self.g, self.b, self.a] - } -} - -/// Represents RGBA screen colors with floating point numbers. -/// -/// All components must be between 0.0 and 1.0. -/// An alpha value of 1.0 is opaque while 0.0 is fully transparent. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct ColorF { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} - -#[allow(missing_docs)] -impl ColorF { - pub const BLACK: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }; - pub const TRANSPARENT: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }; - pub const WHITE: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }; - - /// Constructs a new `ColorF` from its components. - pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self { - ColorF { r, g, b, a } - } - - /// Multiply the RGB channels (but not alpha) with a given factor. - pub fn scale_rgb(&self, scale: f32) -> Self { - ColorF { - r: self.r * scale, - g: self.g * scale, - b: self.b * scale, - a: self.a, - } - } - - // Scale the alpha by a given factor. - pub fn scale_alpha(&self, scale: f32) -> Self { - ColorF { - r: self.r, - g: self.g, - b: self.b, - a: self.a * scale, - } - } - - pub fn to_array(&self) -> [f32; 4] { - [self.r, self.g, self.b, self.a] - } - - /// Multiply the RGB components with the alpha channel. - pub fn premultiplied(&self) -> PremultipliedColorF { - let c = self.scale_rgb(self.a); - PremultipliedColorF { r: c.r, g: c.g, b: c.b, a: c.a } - } -} - -// Floats don't impl Hash/Eq/Ord... -impl Eq for PremultipliedColorF {} -impl Ord for PremultipliedColorF { - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal) - } -} - -#[cfg_attr(feature = "cargo-clippy", allow(clippy::derive_hash_xor_eq))] -impl Hash for PremultipliedColorF { - fn hash<H: Hasher>(&self, state: &mut H) { - // Note: this is inconsistent with the Eq impl for -0.0 (don't care). - self.r.to_bits().hash(state); - self.g.to_bits().hash(state); - self.b.to_bits().hash(state); - self.a.to_bits().hash(state); - } -} - -/// Represents RGBA screen colors with one byte per channel. -/// -/// If the alpha value `a` is 255 the color is opaque. -#[repr(C)] -#[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub struct ColorU { - pub r: u8, - pub g: u8, - pub b: u8, - pub a: u8, -} - -impl ColorU { - /// Constructs a new additive `ColorU` from its components. - pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self { - ColorU { r, g, b, a } - } -} - -fn round_to_int(x: f32) -> u8 { - debug_assert!((0.0 <= x) && (x <= 1.0), "{} should be between 0 and 1", x); - let f = (255.0 * x) + 0.5; - let val = f.floor(); - debug_assert!(val <= 255.0); - val as u8 -} - -// TODO: We shouldn't really convert back to `ColorU` ever, -// since it's lossy. One of the blockers is that all of our debug colors -// are specified in `ColorF`. Changing it to `ColorU` would be nice. -impl From<ColorF> for ColorU { - fn from(color: ColorF) -> Self { - ColorU { - r: round_to_int(color.r), - g: round_to_int(color.g), - b: round_to_int(color.b), - a: round_to_int(color.a), - } - } -} - -impl From<ColorU> for ColorF { - fn from(color: ColorU) -> Self { - ColorF { - r: color.r as f32 / 255.0, - g: color.g as f32 / 255.0, - b: color.b as f32 / 255.0, - a: color.a as f32 / 255.0, - } - } -} diff --git a/third_party/webrender/webrender_api/src/display_item.rs b/third_party/webrender/webrender_api/src/display_item.rs deleted file mode 100644 index 5c425b9ed17..00000000000 --- a/third_party/webrender/webrender_api/src/display_item.rs +++ /dev/null @@ -1,1738 +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 http://mozilla.org/MPL/2.0/. */ - -use euclid::{SideOffsets2D, Angle}; -use peek_poke::PeekPoke; -use std::ops::Not; -// local imports -use crate::font; -use crate::{PipelineId, PropertyBinding}; -use crate::color::ColorF; -use crate::image::{ColorDepth, ImageKey}; -use crate::units::*; -use std::hash::{Hash, Hasher}; - -// ****************************************************************** -// * NOTE: some of these structs have an "IMPLICIT" comment. * -// * This indicates that the BuiltDisplayList will have serialized * -// * a list of values nearby that this item consumes. The traversal * -// * iterator should handle finding these. DebugDisplayItem should * -// * make them explicit. * -// ****************************************************************** - -/// A tag that can be used to identify items during hit testing. If the tag -/// is missing then the item doesn't take part in hit testing at all. This -/// is composed of two numbers. In Servo, the first is an identifier while the -/// second is used to select the cursor that should be used during mouse -/// movement. In Gecko, the first is a scrollframe identifier, while the second -/// is used to store various flags that APZ needs to properly process input -/// events. -pub type ItemTag = (u64, u16); - -/// An identifier used to refer to previously sent display items. Currently it -/// refers to individual display items, but this may change later. -pub type ItemKey = u16; - -bitflags! { - #[repr(C)] - #[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)] - pub struct PrimitiveFlags: u8 { - /// The CSS backface-visibility property (yes, it can be really granular) - const IS_BACKFACE_VISIBLE = 1 << 0; - /// If set, this primitive represents a scroll bar container - const IS_SCROLLBAR_CONTAINER = 1 << 1; - /// If set, this primitive represents a scroll bar thumb - const IS_SCROLLBAR_THUMB = 1 << 2; - /// This is used as a performance hint - this primitive may be promoted to a native - /// compositor surface under certain (implementation specific) conditions. This - /// is typically used for large videos, and canvas elements. - const PREFER_COMPOSITOR_SURFACE = 1 << 3; - /// If set, this primitive can be passed directly to the compositor via its - /// ExternalImageId, and the compositor will use the native image directly. - /// Used as a further extension on top of PREFER_COMPOSITOR_SURFACE. - const SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE = 1 << 4; - } -} - -impl Default for PrimitiveFlags { - fn default() -> Self { - PrimitiveFlags::IS_BACKFACE_VISIBLE - } -} - -/// A grouping of fields a lot of display items need, just to avoid -/// repeating these over and over in this file. -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct CommonItemProperties { - /// Bounds of the display item to clip to. Many items are logically - /// infinite, and rely on this clip_rect to define their bounds - /// (solid colors, background-images, gradients, etc). - pub clip_rect: LayoutRect, - /// Additional clips - pub clip_id: ClipId, - /// The coordinate-space the item is in (yes, it can be really granular) - pub spatial_id: SpatialId, - /// Various flags describing properties of this primitive. - pub flags: PrimitiveFlags, -} - -impl CommonItemProperties { - /// Convenience for tests. - pub fn new( - clip_rect: LayoutRect, - space_and_clip: SpaceAndClipInfo, - ) -> Self { - Self { - clip_rect, - spatial_id: space_and_clip.spatial_id, - clip_id: space_and_clip.clip_id, - flags: PrimitiveFlags::default(), - } - } -} - -/// Per-primitive information about the nodes in the clip tree and -/// the spatial tree that the primitive belongs to. -/// -/// Note: this is a separate struct from `PrimitiveInfo` because -/// it needs indirectional mapping during the DL flattening phase, -/// turning into `ScrollNodeAndClipChain`. -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct SpaceAndClipInfo { - pub spatial_id: SpatialId, - pub clip_id: ClipId, -} - -impl SpaceAndClipInfo { - /// Create a new space/clip info associated with the root - /// scroll frame. - pub fn root_scroll(pipeline_id: PipelineId) -> Self { - SpaceAndClipInfo { - spatial_id: SpatialId::root_scroll_node(pipeline_id), - clip_id: ClipId::root(pipeline_id), - } - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum DisplayItem { - // These are the "real content" display items - Rectangle(RectangleDisplayItem), - ClearRectangle(ClearRectangleDisplayItem), - HitTest(HitTestDisplayItem), - Text(TextDisplayItem), - Line(LineDisplayItem), - Border(BorderDisplayItem), - BoxShadow(BoxShadowDisplayItem), - PushShadow(PushShadowDisplayItem), - Gradient(GradientDisplayItem), - RadialGradient(RadialGradientDisplayItem), - ConicGradient(ConicGradientDisplayItem), - Image(ImageDisplayItem), - RepeatingImage(RepeatingImageDisplayItem), - YuvImage(YuvImageDisplayItem), - BackdropFilter(BackdropFilterDisplayItem), - - // Clips - RectClip(RectClipDisplayItem), - RoundedRectClip(RoundedRectClipDisplayItem), - ImageMaskClip(ImageMaskClipDisplayItem), - Clip(ClipDisplayItem), - ClipChain(ClipChainItem), - - // Spaces and Frames that content can be scoped under. - ScrollFrame(ScrollFrameDisplayItem), - StickyFrame(StickyFrameDisplayItem), - Iframe(IframeDisplayItem), - PushReferenceFrame(ReferenceFrameDisplayListItem), - PushStackingContext(PushStackingContextDisplayItem), - - // These marker items indicate an array of data follows, to be used for the - // next non-marker item. - SetGradientStops, - SetFilterOps, - SetFilterData, - SetFilterPrimitives, - SetPoints, - - // These marker items terminate a scope introduced by a previous item. - PopReferenceFrame, - PopStackingContext, - PopAllShadows, - - ReuseItems(ItemKey), - RetainedItems(ItemKey), -} - -/// This is a "complete" version of the DisplayItem, with all implicit trailing -/// arrays included, for debug serialization (captures). -#[cfg(any(feature = "serialize", feature = "deserialize"))] -#[cfg_attr(feature = "serialize", derive(Serialize))] -#[cfg_attr(feature = "deserialize", derive(Deserialize))] -pub enum DebugDisplayItem { - Rectangle(RectangleDisplayItem), - ClearRectangle(ClearRectangleDisplayItem), - HitTest(HitTestDisplayItem), - Text(TextDisplayItem, Vec<font::GlyphInstance>), - Line(LineDisplayItem), - Border(BorderDisplayItem), - BoxShadow(BoxShadowDisplayItem), - PushShadow(PushShadowDisplayItem), - Gradient(GradientDisplayItem), - RadialGradient(RadialGradientDisplayItem), - ConicGradient(ConicGradientDisplayItem), - Image(ImageDisplayItem), - RepeatingImage(RepeatingImageDisplayItem), - YuvImage(YuvImageDisplayItem), - BackdropFilter(BackdropFilterDisplayItem), - - ImageMaskClip(ImageMaskClipDisplayItem), - RoundedRectClip(RoundedRectClipDisplayItem), - RectClip(RectClipDisplayItem), - Clip(ClipDisplayItem, Vec<ComplexClipRegion>), - ClipChain(ClipChainItem, Vec<ClipId>), - - ScrollFrame(ScrollFrameDisplayItem), - StickyFrame(StickyFrameDisplayItem), - Iframe(IframeDisplayItem), - PushReferenceFrame(ReferenceFrameDisplayListItem), - PushStackingContext(PushStackingContextDisplayItem), - - SetGradientStops(Vec<GradientStop>), - SetFilterOps(Vec<FilterOp>), - SetFilterData(FilterData), - SetFilterPrimitives(Vec<FilterPrimitive>), - SetPoints(Vec<LayoutPoint>), - - PopReferenceFrame, - PopStackingContext, - PopAllShadows, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ImageMaskClipDisplayItem { - pub id: ClipId, - pub parent_space_and_clip: SpaceAndClipInfo, - pub image_mask: ImageMask, - pub fill_rule: FillRule, -} // IMPLICIT points: Vec<LayoutPoint> - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RectClipDisplayItem { - pub id: ClipId, - pub parent_space_and_clip: SpaceAndClipInfo, - pub clip_rect: LayoutRect, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RoundedRectClipDisplayItem { - pub id: ClipId, - pub parent_space_and_clip: SpaceAndClipInfo, - pub clip: ComplexClipRegion, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ClipDisplayItem { - pub id: ClipId, - pub parent_space_and_clip: SpaceAndClipInfo, - pub clip_rect: LayoutRect, -} // IMPLICIT: complex_clips: Vec<ComplexClipRegion> - -/// The minimum and maximum allowable offset for a sticky frame in a single dimension. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct StickyOffsetBounds { - /// The minimum offset for this frame, typically a negative value, which specifies how - /// far in the negative direction the sticky frame can offset its contents in this - /// dimension. - pub min: f32, - - /// The maximum offset for this frame, typically a positive value, which specifies how - /// far in the positive direction the sticky frame can offset its contents in this - /// dimension. - pub max: f32, -} - -impl StickyOffsetBounds { - pub fn new(min: f32, max: f32) -> StickyOffsetBounds { - StickyOffsetBounds { min, max } - } -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct StickyFrameDisplayItem { - pub id: SpatialId, - pub parent_spatial_id: SpatialId, - pub bounds: LayoutRect, - - /// The margins that should be maintained between the edge of the parent viewport and this - /// sticky frame. A margin of None indicates that the sticky frame should not stick at all - /// to that particular edge of the viewport. - pub margins: SideOffsets2D<Option<f32>, LayoutPixel>, - - /// The minimum and maximum vertical offsets for this sticky frame. Ignoring these constraints, - /// the sticky frame will continue to stick to the edge of the viewport as its original - /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the - /// original position relative to non-sticky content within the same scrolling frame. - pub vertical_offset_bounds: StickyOffsetBounds, - - /// The minimum and maximum horizontal offsets for this sticky frame. Ignoring these constraints, - /// the sticky frame will continue to stick to the edge of the viewport as its original - /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the - /// original position relative to non-sticky content within the same scrolling frame. - pub horizontal_offset_bounds: StickyOffsetBounds, - - /// The amount of offset that has already been applied to the sticky frame. A positive y - /// component this field means that a top-sticky item was in a scrollframe that has been - /// scrolled down, such that the sticky item's position needed to be offset downwards by - /// `previously_applied_offset.y`. A negative y component corresponds to the upward offset - /// applied due to bottom-stickiness. The x-axis works analogously. - pub previously_applied_offset: LayoutVector2D, -} - -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum ScrollSensitivity { - ScriptAndInputEvents, - Script, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ScrollFrameDisplayItem { - /// The id of the clip this scroll frame creates - pub clip_id: ClipId, - /// The id of the space this scroll frame creates - pub scroll_frame_id: SpatialId, - /// The size of the contents this contains (so the backend knows how far it can scroll). - // FIXME: this can *probably* just be a size? Origin seems to just get thrown out. - pub content_rect: LayoutRect, - pub clip_rect: LayoutRect, - pub parent_space_and_clip: SpaceAndClipInfo, - pub external_id: ExternalScrollId, - pub scroll_sensitivity: ScrollSensitivity, - /// The amount this scrollframe has already been scrolled by, in the caller. - /// This means that all the display items that are inside the scrollframe - /// will have their coordinates shifted by this amount, and this offset - /// should be added to those display item coordinates in order to get a - /// normalized value that is consistent across display lists. - pub external_scroll_offset: LayoutVector2D, -} - -/// A solid or an animating color to draw (may not actually be a rectangle due to complex clips) -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RectangleDisplayItem { - pub common: CommonItemProperties, - pub bounds: LayoutRect, - pub color: PropertyBinding<ColorF>, -} - -/// Clears all colors from the area, making it possible to cut holes in the window. -/// (useful for things like the macos frosted-glass effect). -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ClearRectangleDisplayItem { - pub common: CommonItemProperties, - pub bounds: LayoutRect, -} - -/// A minimal hit-testable item for the parent browser's convenience, and is -/// slimmer than a RectangleDisplayItem (no color). The existence of this as a -/// distinct item also makes it easier to inspect/debug display items. -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct HitTestDisplayItem { - pub common: CommonItemProperties, - pub tag: ItemTag, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct LineDisplayItem { - pub common: CommonItemProperties, - /// We need a separate rect from common.clip_rect to encode cute - /// tricks that firefox does to make a series of text-decorations seamlessly - /// line up -- snapping the decorations to a multiple of their period, and - /// then clipping them to their "proper" area. This rect is that "logical" - /// snapped area that may be clipped to the right size by the clip_rect. - pub area: LayoutRect, - /// Whether the rect is interpretted as vertical or horizontal - pub orientation: LineOrientation, - /// This could potentially be implied from area, but we currently prefer - /// that this is the responsibility of the layout engine. Value irrelevant - /// for non-wavy lines. - // FIXME: this was done before we could use tagged unions in enums, but now - // it should just be part of LineStyle::Wavy. - pub wavy_line_thickness: f32, - pub color: ColorF, - pub style: LineStyle, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] -pub enum LineOrientation { - Vertical, - Horizontal, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] -pub enum LineStyle { - Solid, - Dotted, - Dashed, - Wavy, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct TextDisplayItem { - pub common: CommonItemProperties, - /// The area all the glyphs should be found in. Strictly speaking this isn't - /// necessarily needed, but layout engines should already "know" this, and we - /// use it cull and size things quickly before glyph layout is done. Currently - /// the glyphs *can* be outside these bounds, but that should imply they - /// can be cut off. - // FIXME: these are currently sometimes ignored to keep some old wrench tests - // working, but we should really just fix the tests! - pub bounds: LayoutRect, - pub font_key: font::FontInstanceKey, - pub color: ColorF, - pub glyph_options: Option<font::GlyphOptions>, -} // IMPLICIT: glyphs: Vec<font::GlyphInstance> - -#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct NormalBorder { - pub left: BorderSide, - pub right: BorderSide, - pub top: BorderSide, - pub bottom: BorderSide, - pub radius: BorderRadius, - /// Whether to apply anti-aliasing on the border corners. - /// - /// Note that for this to be `false` and work, this requires the borders to - /// be solid, and no border-radius. - pub do_aa: bool, -} - -impl NormalBorder { - fn can_disable_antialiasing(&self) -> bool { - fn is_valid(style: BorderStyle) -> bool { - style == BorderStyle::Solid || style == BorderStyle::None - } - - self.radius.is_zero() && - is_valid(self.top.style) && - is_valid(self.left.style) && - is_valid(self.bottom.style) && - is_valid(self.right.style) - } - - /// Normalizes a border so that we don't render disallowed stuff, like inset - /// borders that are less than two pixels wide. - #[inline] - pub fn normalize(&mut self, widths: &LayoutSideOffsets) { - debug_assert!( - self.do_aa || self.can_disable_antialiasing(), - "Unexpected disabled-antialiasing in a border, likely won't work or will be ignored" - ); - - #[inline] - fn renders_small_border_solid(style: BorderStyle) -> bool { - match style { - BorderStyle::Groove | - BorderStyle::Ridge => true, - _ => false, - } - } - - let normalize_side = |side: &mut BorderSide, width: f32| { - if renders_small_border_solid(side.style) && width < 2. { - side.style = BorderStyle::Solid; - } - }; - - normalize_side(&mut self.left, widths.left); - normalize_side(&mut self.right, widths.right); - normalize_side(&mut self.top, widths.top); - normalize_side(&mut self.bottom, widths.bottom); - } -} - -#[repr(u8)] -#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)] -pub enum RepeatMode { - Stretch, - Repeat, - Round, - Space, -} - -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum NinePatchBorderSource { - Image(ImageKey), - Gradient(Gradient), - RadialGradient(RadialGradient), - ConicGradient(ConicGradient), -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct NinePatchBorder { - /// Describes what to use as the 9-patch source image. If this is an image, - /// it will be stretched to fill the size given by width x height. - pub source: NinePatchBorderSource, - - /// The width of the 9-part image. - pub width: i32, - - /// The height of the 9-part image. - pub height: i32, - - /// Distances from each edge where the image should be sliced up. These - /// values are in 9-part-image space (the same space as width and height), - /// and the resulting image parts will be used to fill the corresponding - /// parts of the border as given by the border widths. This can lead to - /// stretching. - /// Slices can be overlapping. In that case, the same pixels from the - /// 9-part image will show up in multiple parts of the resulting border. - pub slice: DeviceIntSideOffsets, - - /// Controls whether the center of the 9 patch image is rendered or - /// ignored. The center is never rendered if the slices are overlapping. - pub fill: bool, - - /// Determines what happens if the horizontal side parts of the 9-part - /// image have a different size than the horizontal parts of the border. - pub repeat_horizontal: RepeatMode, - - /// Determines what happens if the vertical side parts of the 9-part - /// image have a different size than the vertical parts of the border. - pub repeat_vertical: RepeatMode, - - /// The outset for the border. - /// TODO(mrobinson): This should be removed and handled by the client. - pub outset: LayoutSideOffsets, // TODO: what unit is this in? -} - -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum BorderDetails { - Normal(NormalBorder), - NinePatch(NinePatchBorder), -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct BorderDisplayItem { - pub common: CommonItemProperties, - pub bounds: LayoutRect, - pub widths: LayoutSideOffsets, - pub details: BorderDetails, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum BorderRadiusKind { - Uniform, - NonUniform, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct BorderRadius { - pub top_left: LayoutSize, - pub top_right: LayoutSize, - pub bottom_left: LayoutSize, - pub bottom_right: LayoutSize, -} - -impl Default for BorderRadius { - fn default() -> Self { - BorderRadius { - top_left: LayoutSize::zero(), - top_right: LayoutSize::zero(), - bottom_left: LayoutSize::zero(), - bottom_right: LayoutSize::zero(), - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct BorderSide { - pub color: ColorF, - pub style: BorderStyle, -} - -#[repr(u32)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq, PeekPoke)] -pub enum BorderStyle { - None = 0, - Solid = 1, - Double = 2, - Dotted = 3, - Dashed = 4, - Hidden = 5, - Groove = 6, - Ridge = 7, - Inset = 8, - Outset = 9, -} - -impl BorderStyle { - pub fn is_hidden(self) -> bool { - self == BorderStyle::Hidden || self == BorderStyle::None - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum BoxShadowClipMode { - Outset = 0, - Inset = 1, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct BoxShadowDisplayItem { - pub common: CommonItemProperties, - pub box_bounds: LayoutRect, - pub offset: LayoutVector2D, - pub color: ColorF, - pub blur_radius: f32, - pub spread_radius: f32, - pub border_radius: BorderRadius, - pub clip_mode: BoxShadowClipMode, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct PushShadowDisplayItem { - pub space_and_clip: SpaceAndClipInfo, - pub shadow: Shadow, - pub should_inflate: bool, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct Shadow { - pub offset: LayoutVector2D, - pub color: ColorF, - pub blur_radius: f32, -} - -#[repr(u8)] -#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)] -pub enum ExtendMode { - Clamp, - Repeat, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct Gradient { - pub start_point: LayoutPoint, - pub end_point: LayoutPoint, - pub extend_mode: ExtendMode, -} // IMPLICIT: stops: Vec<GradientStop> - -impl Gradient { - pub fn is_valid(&self) -> bool { - self.start_point.x.is_finite() && - self.start_point.y.is_finite() && - self.end_point.x.is_finite() && - self.end_point.y.is_finite() - } -} - -/// The area -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct GradientDisplayItem { - /// NOTE: common.clip_rect is the area the gradient covers - pub common: CommonItemProperties, - /// The area to tile the gradient over (first tile starts at origin of this rect) - // FIXME: this should ideally just be `tile_origin` here, with the clip_rect - // defining the bounds of the item. Needs non-trivial backend changes. - pub bounds: LayoutRect, - /// How big a tile of the of the gradient should be (common case: bounds.size) - pub tile_size: LayoutSize, - /// The space between tiles of the gradient (common case: 0) - pub tile_spacing: LayoutSize, - pub gradient: Gradient, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct GradientStop { - pub offset: f32, - pub color: ColorF, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RadialGradient { - pub center: LayoutPoint, - pub radius: LayoutSize, - pub start_offset: f32, - pub end_offset: f32, - pub extend_mode: ExtendMode, -} // IMPLICIT stops: Vec<GradientStop> - -impl RadialGradient { - pub fn is_valid(&self) -> bool { - self.center.x.is_finite() && - self.center.y.is_finite() && - self.start_offset.is_finite() && - self.end_offset.is_finite() - } -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ConicGradient { - pub center: LayoutPoint, - pub angle: f32, - pub start_offset: f32, - pub end_offset: f32, - pub extend_mode: ExtendMode, -} // IMPLICIT stops: Vec<GradientStop> - -impl ConicGradient { - pub fn is_valid(&self) -> bool { - self.center.x.is_finite() && - self.center.y.is_finite() && - self.angle.is_finite() && - self.start_offset.is_finite() && - self.end_offset.is_finite() - } -} - -/// Just an abstraction for bundling up a bunch of clips into a "super clip". -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ClipChainItem { - pub id: ClipChainId, - pub parent: Option<ClipChainId>, -} // IMPLICIT clip_ids: Vec<ClipId> - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RadialGradientDisplayItem { - pub common: CommonItemProperties, - /// The area to tile the gradient over (first tile starts at origin of this rect) - // FIXME: this should ideally just be `tile_origin` here, with the clip_rect - // defining the bounds of the item. Needs non-trivial backend changes. - pub bounds: LayoutRect, - pub gradient: RadialGradient, - pub tile_size: LayoutSize, - pub tile_spacing: LayoutSize, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ConicGradientDisplayItem { - pub common: CommonItemProperties, - /// The area to tile the gradient over (first tile starts at origin of this rect) - // FIXME: this should ideally just be `tile_origin` here, with the clip_rect - // defining the bounds of the item. Needs non-trivial backend changes. - pub bounds: LayoutRect, - pub gradient: ConicGradient, - pub tile_size: LayoutSize, - pub tile_spacing: LayoutSize, -} - -/// Renders a filtered region of its backdrop -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct BackdropFilterDisplayItem { - pub common: CommonItemProperties, -} -// IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive> - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ReferenceFrameDisplayListItem { - pub origin: LayoutPoint, - pub parent_spatial_id: SpatialId, - pub reference_frame: ReferenceFrame, -} - -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum ReferenceFrameKind { - /// A normal transform matrix, may contain perspective (the CSS transform property) - Transform { - /// Optionally marks the transform as only ever having a simple 2D scale or translation, - /// allowing for optimizations. - is_2d_scale_translation: bool, - /// Marks that the transform should be snapped. Used for transforms which animate in - /// response to scrolling, eg for zooming or dynamic toolbar fixed-positioning. - should_snap: bool, - }, - /// A perspective transform, that optionally scrolls relative to a specific scroll node - Perspective { - scrolling_relative_to: Option<ExternalScrollId>, - } -} - -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum Rotation { - Degree0, - Degree90, - Degree180, - Degree270, -} - -impl Rotation { - pub fn to_matrix( - &self, - size: LayoutSize, - ) -> LayoutTransform { - let (shift_center_to_origin, angle) = match self { - Rotation::Degree0 => { - (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.)) - }, - Rotation::Degree90 => { - (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.)) - }, - Rotation::Degree180 => { - (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.)) - }, - Rotation::Degree270 => { - (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.)) - }, - }; - let shift_origin_to_center = LayoutTransform::translation(size.width / 2., size.height / 2., 0.); - - shift_center_to_origin - .then(&LayoutTransform::rotation(0., 0., 1.0, angle)) - .then(&shift_origin_to_center) - } -} - -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum ReferenceTransformBinding { - /// Standard reference frame which contains a precomputed transform. - Static { - binding: PropertyBinding<LayoutTransform>, - }, - /// Computed reference frame which dynamically calculates the transform - /// based on the given parameters. The reference is the content size of - /// the parent iframe, which is affected by snapping. - Computed { - scale_from: Option<LayoutSize>, - vertical_flip: bool, - rotation: Rotation, - }, -} - -impl Default for ReferenceTransformBinding { - fn default() -> Self { - ReferenceTransformBinding::Static { - binding: Default::default(), - } - } -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ReferenceFrame { - pub kind: ReferenceFrameKind, - pub transform_style: TransformStyle, - /// The transform matrix, either the perspective matrix or the transform - /// matrix. - pub transform: ReferenceTransformBinding, - pub id: SpatialId, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct PushStackingContextDisplayItem { - pub origin: LayoutPoint, - pub spatial_id: SpatialId, - pub prim_flags: PrimitiveFlags, - pub stacking_context: StackingContext, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct StackingContext { - pub transform_style: TransformStyle, - pub mix_blend_mode: MixBlendMode, - pub clip_id: Option<ClipId>, - pub raster_space: RasterSpace, - pub flags: StackingContextFlags, -} -// IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive> - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] -pub enum TransformStyle { - Flat = 0, - Preserve3D = 1, -} - -/// Configure whether the contents of a stacking context -/// should be rasterized in local space or screen space. -/// Local space rasterized pictures are typically used -/// when we want to cache the output, and performance is -/// important. Note that this is a performance hint only, -/// which WR may choose to ignore. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, MallocSizeOf, Serialize, PeekPoke)] -#[repr(u8)] -pub enum RasterSpace { - // Rasterize in local-space, applying supplied scale to primitives. - // Best performance, but lower quality. - Local(f32), - - // Rasterize the picture in screen-space, including rotation / skew etc in - // the rasterized element. Best quality, but slower performance. Note that - // any stacking context with a perspective transform will be rasterized - // in local-space, even if this is set. - Screen, -} - -impl RasterSpace { - pub fn local_scale(self) -> Option<f32> { - match self { - RasterSpace::Local(scale) => Some(scale), - RasterSpace::Screen => None, - } - } -} - -impl Eq for RasterSpace {} - -impl Hash for RasterSpace { - fn hash<H: Hasher>(&self, state: &mut H) { - match self { - RasterSpace::Screen => { - 0.hash(state); - } - RasterSpace::Local(scale) => { - // Note: this is inconsistent with the Eq impl for -0.0 (don't care). - 1.hash(state); - scale.to_bits().hash(state); - } - } - } -} - -bitflags! { - #[repr(C)] - #[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)] - pub struct StackingContextFlags: u8 { - /// If true, this stacking context represents a backdrop root, per the CSS - /// filter-effects specification (see https://drafts.fxtf.org/filter-effects-2/#BackdropRoot). - const IS_BACKDROP_ROOT = 1 << 0; - /// If true, this stacking context is a blend container than contains - /// mix-blend-mode children (and should thus be isolated). - const IS_BLEND_CONTAINER = 1 << 1; - } -} - -impl Default for StackingContextFlags { - fn default() -> Self { - StackingContextFlags::empty() - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum MixBlendMode { - Normal = 0, - Multiply = 1, - Screen = 2, - Overlay = 3, - Darken = 4, - Lighten = 5, - ColorDodge = 6, - ColorBurn = 7, - HardLight = 8, - SoftLight = 9, - Difference = 10, - Exclusion = 11, - Hue = 12, - Saturation = 13, - Color = 14, - Luminosity = 15, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum ColorSpace { - Srgb, - LinearRgb, -} - -/// Available composite operoations for the composite filter primitive -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum CompositeOperator { - Over, - In, - Atop, - Out, - Xor, - Lighter, - Arithmetic([f32; 4]), -} - -impl CompositeOperator { - // This must stay in sync with the composite operator defines in cs_svg_filter.glsl - pub fn as_int(&self) -> u32 { - match self { - CompositeOperator::Over => 0, - CompositeOperator::In => 1, - CompositeOperator::Out => 2, - CompositeOperator::Atop => 3, - CompositeOperator::Xor => 4, - CompositeOperator::Lighter => 5, - CompositeOperator::Arithmetic(..) => 6, - } - } -} - -/// An input to a SVG filter primitive. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum FilterPrimitiveInput { - /// The input is the original graphic that the filter is being applied to. - Original, - /// The input is the output of the previous filter primitive in the filter primitive chain. - Previous, - /// The input is the output of the filter primitive at the given index in the filter primitive chain. - OutputOfPrimitiveIndex(usize), -} - -impl FilterPrimitiveInput { - /// Gets the index of the input. - /// Returns `None` if the source graphic is the input. - pub fn to_index(self, cur_index: usize) -> Option<usize> { - match self { - FilterPrimitiveInput::Previous if cur_index > 0 => Some(cur_index - 1), - FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => Some(index), - _ => None, - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct BlendPrimitive { - pub input1: FilterPrimitiveInput, - pub input2: FilterPrimitiveInput, - pub mode: MixBlendMode, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct FloodPrimitive { - pub color: ColorF, -} - -impl FloodPrimitive { - pub fn sanitize(&mut self) { - self.color.r = self.color.r.min(1.0).max(0.0); - self.color.g = self.color.g.min(1.0).max(0.0); - self.color.b = self.color.b.min(1.0).max(0.0); - self.color.a = self.color.a.min(1.0).max(0.0); - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct BlurPrimitive { - pub input: FilterPrimitiveInput, - pub width: f32, - pub height: f32, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct OpacityPrimitive { - pub input: FilterPrimitiveInput, - pub opacity: f32, -} - -impl OpacityPrimitive { - pub fn sanitize(&mut self) { - self.opacity = self.opacity.min(1.0).max(0.0); - } -} - -/// cbindgen:derive-eq=false -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ColorMatrixPrimitive { - pub input: FilterPrimitiveInput, - pub matrix: [f32; 20], -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct DropShadowPrimitive { - pub input: FilterPrimitiveInput, - pub shadow: Shadow, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ComponentTransferPrimitive { - pub input: FilterPrimitiveInput, - // Component transfer data is stored in FilterData. -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct IdentityPrimitive { - pub input: FilterPrimitiveInput, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct OffsetPrimitive { - pub input: FilterPrimitiveInput, - pub offset: LayoutVector2D, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct CompositePrimitive { - pub input1: FilterPrimitiveInput, - pub input2: FilterPrimitiveInput, - pub operator: CompositeOperator, -} - -/// See: https://github.com/eqrion/cbindgen/issues/9 -/// cbindgen:derive-eq=false -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] -pub enum FilterPrimitiveKind { - Identity(IdentityPrimitive), - Blend(BlendPrimitive), - Flood(FloodPrimitive), - Blur(BlurPrimitive), - // TODO: Support animated opacity? - Opacity(OpacityPrimitive), - /// cbindgen:derive-eq=false - ColorMatrix(ColorMatrixPrimitive), - DropShadow(DropShadowPrimitive), - ComponentTransfer(ComponentTransferPrimitive), - Offset(OffsetPrimitive), - Composite(CompositePrimitive), -} - -impl Default for FilterPrimitiveKind { - fn default() -> Self { - FilterPrimitiveKind::Identity(IdentityPrimitive::default()) - } -} - -impl FilterPrimitiveKind { - pub fn sanitize(&mut self) { - match self { - FilterPrimitiveKind::Flood(flood) => flood.sanitize(), - FilterPrimitiveKind::Opacity(opacity) => opacity.sanitize(), - - // No sanitization needed. - FilterPrimitiveKind::Identity(..) | - FilterPrimitiveKind::Blend(..) | - FilterPrimitiveKind::ColorMatrix(..) | - FilterPrimitiveKind::Offset(..) | - FilterPrimitiveKind::Composite(..) | - FilterPrimitiveKind::Blur(..) | - FilterPrimitiveKind::DropShadow(..) | - // Component transfer's filter data is sanitized separately. - FilterPrimitiveKind::ComponentTransfer(..) => {} - } - } -} - -/// SVG Filter Primitive. -/// See: https://github.com/eqrion/cbindgen/issues/9 -/// cbindgen:derive-eq=false -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct FilterPrimitive { - pub kind: FilterPrimitiveKind, - pub color_space: ColorSpace, -} - -impl FilterPrimitive { - pub fn sanitize(&mut self) { - self.kind.sanitize(); - } -} - -/// CSS filter. -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)] -pub enum FilterOp { - /// Filter that does no transformation of the colors, needed for - /// debug purposes only. - Identity, - Blur(f32, f32), - Brightness(f32), - Contrast(f32), - Grayscale(f32), - HueRotate(f32), - Invert(f32), - Opacity(PropertyBinding<f32>, f32), - Saturate(f32), - Sepia(f32), - DropShadow(Shadow), - ColorMatrix([f32; 20]), - SrgbToLinear, - LinearToSrgb, - ComponentTransfer, - Flood(ColorF), -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)] -pub enum ComponentTransferFuncType { - Identity = 0, - Table = 1, - Discrete = 2, - Linear = 3, - Gamma = 4, -} - -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct FilterData { - pub func_r_type: ComponentTransferFuncType, - pub r_values: Vec<f32>, - pub func_g_type: ComponentTransferFuncType, - pub g_values: Vec<f32>, - pub func_b_type: ComponentTransferFuncType, - pub b_values: Vec<f32>, - pub func_a_type: ComponentTransferFuncType, - pub a_values: Vec<f32>, -} - -fn sanitize_func_type( - func_type: ComponentTransferFuncType, - values: &[f32], -) -> ComponentTransferFuncType { - if values.is_empty() { - return ComponentTransferFuncType::Identity; - } - if values.len() < 2 && func_type == ComponentTransferFuncType::Linear { - return ComponentTransferFuncType::Identity; - } - if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma { - return ComponentTransferFuncType::Identity; - } - func_type -} - -fn sanitize_values( - func_type: ComponentTransferFuncType, - values: &[f32], -) -> bool { - if values.len() < 2 && func_type == ComponentTransferFuncType::Linear { - return false; - } - if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma { - return false; - } - true -} - -impl FilterData { - /// Ensure that the number of values matches up with the function type. - pub fn sanitize(&self) -> FilterData { - FilterData { - func_r_type: sanitize_func_type(self.func_r_type, &self.r_values), - r_values: - if sanitize_values(self.func_r_type, &self.r_values) { - self.r_values.clone() - } else { - Vec::new() - }, - func_g_type: sanitize_func_type(self.func_g_type, &self.g_values), - g_values: - if sanitize_values(self.func_g_type, &self.g_values) { - self.g_values.clone() - } else { - Vec::new() - }, - - func_b_type: sanitize_func_type(self.func_b_type, &self.b_values), - b_values: - if sanitize_values(self.func_b_type, &self.b_values) { - self.b_values.clone() - } else { - Vec::new() - }, - - func_a_type: sanitize_func_type(self.func_a_type, &self.a_values), - a_values: - if sanitize_values(self.func_a_type, &self.a_values) { - self.a_values.clone() - } else { - Vec::new() - }, - - } - } - - pub fn is_identity(&self) -> bool { - self.func_r_type == ComponentTransferFuncType::Identity && - self.func_g_type == ComponentTransferFuncType::Identity && - self.func_b_type == ComponentTransferFuncType::Identity && - self.func_a_type == ComponentTransferFuncType::Identity - } -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct IframeDisplayItem { - pub bounds: LayoutRect, - pub clip_rect: LayoutRect, - pub space_and_clip: SpaceAndClipInfo, - pub pipeline_id: PipelineId, - pub ignore_missing_pipeline: bool, -} - -/// This describes an image that fills the specified area. It stretches or shrinks -/// the image as necessary. While RepeatingImageDisplayItem could otherwise provide -/// a superset of the functionality, it has been problematic inferring the desired -/// repetition properties when snapping changes the size of the primitive. -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ImageDisplayItem { - pub common: CommonItemProperties, - /// The area to tile the image over (first tile starts at origin of this rect) - // FIXME: this should ideally just be `tile_origin` here, with the clip_rect - // defining the bounds of the item. Needs non-trivial backend changes. - pub bounds: LayoutRect, - pub image_key: ImageKey, - pub image_rendering: ImageRendering, - pub alpha_type: AlphaType, - /// A hack used by gecko to color a simple bitmap font used for tofu glyphs - pub color: ColorF, -} - -/// This describes a background-image and its tiling. It repeats in a grid to fill -/// the specified area. -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RepeatingImageDisplayItem { - pub common: CommonItemProperties, - /// The area to tile the image over (first tile starts at origin of this rect) - // FIXME: this should ideally just be `tile_origin` here, with the clip_rect - // defining the bounds of the item. Needs non-trivial backend changes. - pub bounds: LayoutRect, - /// How large to make a single tile of the image (common case: bounds.size) - pub stretch_size: LayoutSize, - /// The space between tiles (common case: 0) - pub tile_spacing: LayoutSize, - pub image_key: ImageKey, - pub image_rendering: ImageRendering, - pub alpha_type: AlphaType, - /// A hack used by gecko to color a simple bitmap font used for tofu glyphs - pub color: ColorF, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum ImageRendering { - Auto = 0, - CrispEdges = 1, - Pixelated = 2, -} - -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum AlphaType { - Alpha = 0, - PremultipliedAlpha = 1, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct YuvImageDisplayItem { - pub common: CommonItemProperties, - pub bounds: LayoutRect, - pub yuv_data: YuvData, - pub color_depth: ColorDepth, - pub color_space: YuvColorSpace, - pub color_range: ColorRange, - pub image_rendering: ImageRendering, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum YuvColorSpace { - Rec601 = 0, - Rec709 = 1, - Rec2020 = 2, - Identity = 3, // aka RGB as per ISO/IEC 23091-2:2019 -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum ColorRange { - Limited = 0, - Full = 1, -} - -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] -pub enum YuvData { - NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel) - PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel) - InterleavedYCbCr(ImageKey), // (YCbCr interleaved channel) -} - -impl YuvData { - pub fn get_format(&self) -> YuvFormat { - match *self { - YuvData::NV12(..) => YuvFormat::NV12, - YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr, - YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr, - } - } -} - -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum YuvFormat { - NV12 = 0, - PlanarYCbCr = 1, - InterleavedYCbCr = 2, -} - -impl YuvFormat { - pub fn get_plane_num(self) -> usize { - match self { - YuvFormat::NV12 => 2, - YuvFormat::PlanarYCbCr => 3, - YuvFormat::InterleavedYCbCr => 1, - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ImageMask { - pub image: ImageKey, - pub rect: LayoutRect, - pub repeat: bool, -} - -impl ImageMask { - /// Get a local clipping rect contributed by this mask. - pub fn get_local_clip_rect(&self) -> Option<LayoutRect> { - if self.repeat { - None - } else { - Some(self.rect) - } - } -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)] -pub enum ClipMode { - Clip, // Pixels inside the region are visible. - ClipOut, // Pixels outside the region are visible. -} - -impl Not for ClipMode { - type Output = ClipMode; - - fn not(self) -> ClipMode { - match self { - ClipMode::Clip => ClipMode::ClipOut, - ClipMode::ClipOut => ClipMode::Clip, - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct ComplexClipRegion { - /// The boundaries of the rectangle. - pub rect: LayoutRect, - /// Border radii of this rectangle. - pub radii: BorderRadius, - /// Whether we are clipping inside or outside - /// the region. - pub mode: ClipMode, -} - -impl BorderRadius { - pub fn zero() -> BorderRadius { - BorderRadius { - top_left: LayoutSize::new(0.0, 0.0), - top_right: LayoutSize::new(0.0, 0.0), - bottom_left: LayoutSize::new(0.0, 0.0), - bottom_right: LayoutSize::new(0.0, 0.0), - } - } - - pub fn uniform(radius: f32) -> BorderRadius { - BorderRadius { - top_left: LayoutSize::new(radius, radius), - top_right: LayoutSize::new(radius, radius), - bottom_left: LayoutSize::new(radius, radius), - bottom_right: LayoutSize::new(radius, radius), - } - } - - pub fn uniform_size(radius: LayoutSize) -> BorderRadius { - BorderRadius { - top_left: radius, - top_right: radius, - bottom_left: radius, - bottom_right: radius, - } - } - - pub fn is_uniform(&self) -> Option<f32> { - match self.is_uniform_size() { - Some(radius) if radius.width == radius.height => Some(radius.width), - _ => None, - } - } - - pub fn is_uniform_size(&self) -> Option<LayoutSize> { - let uniform_radius = self.top_left; - if self.top_right == uniform_radius && self.bottom_left == uniform_radius && - self.bottom_right == uniform_radius - { - Some(uniform_radius) - } else { - None - } - } - - /// Return whether, in each corner, the radius in *either* direction is zero. - /// This means that none of the corners are rounded. - pub fn is_zero(&self) -> bool { - let corner_is_zero = |corner: &LayoutSize| corner.width == 0.0 || corner.height == 0.0; - corner_is_zero(&self.top_left) && - corner_is_zero(&self.top_right) && - corner_is_zero(&self.bottom_right) && - corner_is_zero(&self.bottom_left) - } -} - -impl ComplexClipRegion { - /// Create a new complex clip region. - pub fn new( - rect: LayoutRect, - radii: BorderRadius, - mode: ClipMode, - ) -> Self { - ComplexClipRegion { rect, radii, mode } - } -} - -impl ComplexClipRegion { - /// Get a local clipping rect contributed by this clip region. - pub fn get_local_clip_rect(&self) -> Option<LayoutRect> { - match self.mode { - ClipMode::Clip => { - Some(self.rect) - } - ClipMode::ClipOut => { - None - } - } - } -} - -pub const POLYGON_CLIP_VERTEX_MAX: usize = 16; - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] -pub enum FillRule { - Nonzero = 0x1, // Behaves as the SVG fill-rule definition for nonzero. - Evenodd = 0x2, // Behaves as the SVG fill-rule definition for evenodd. -} - -impl From<u8> for FillRule { - fn from(fill_rule: u8) -> Self { - match fill_rule { - 0x1 => FillRule::Nonzero, - 0x2 => FillRule::Evenodd, - _ => panic!("Unexpected FillRule value."), - } - } -} - -impl From<FillRule> for u8 { - fn from(fill_rule: FillRule) -> Self { - match fill_rule { - FillRule::Nonzero => 0x1, - FillRule::Evenodd => 0x2, - } - } -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] -pub struct ClipChainId(pub u64, pub PipelineId); - -/// A reference to a clipping node defining how an item is clipped. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] -pub enum ClipId { - Clip(usize, PipelineId), - ClipChain(ClipChainId), -} - -const ROOT_CLIP_ID: usize = 0; - -impl ClipId { - /// Return the root clip ID - effectively doing no clipping. - pub fn root(pipeline_id: PipelineId) -> Self { - ClipId::Clip(ROOT_CLIP_ID, pipeline_id) - } - - /// Return an invalid clip ID - needed in places where we carry - /// one but need to not attempt to use it. - pub fn invalid() -> Self { - ClipId::Clip(!0, PipelineId::dummy()) - } - - pub fn pipeline_id(&self) -> PipelineId { - match *self { - ClipId::Clip(_, pipeline_id) | - ClipId::ClipChain(ClipChainId(_, pipeline_id)) => pipeline_id, - } - } - - pub fn is_root(&self) -> bool { - match *self { - ClipId::Clip(id, _) => id == ROOT_CLIP_ID, - ClipId::ClipChain(_) => false, - } - } - - pub fn is_valid(&self) -> bool { - match *self { - ClipId::Clip(id, _) => id != !0, - _ => true, - } - } -} - -/// A reference to a spatial node defining item positioning. -#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] -pub struct SpatialId(pub usize, PipelineId); - -const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0; -const ROOT_SCROLL_NODE_SPATIAL_ID: usize = 1; - -impl SpatialId { - pub fn new(spatial_node_index: usize, pipeline_id: PipelineId) -> Self { - SpatialId(spatial_node_index, pipeline_id) - } - - pub fn root_reference_frame(pipeline_id: PipelineId) -> Self { - SpatialId(ROOT_REFERENCE_FRAME_SPATIAL_ID, pipeline_id) - } - - pub fn root_scroll_node(pipeline_id: PipelineId) -> Self { - SpatialId(ROOT_SCROLL_NODE_SPATIAL_ID, pipeline_id) - } - - pub fn pipeline_id(&self) -> PipelineId { - self.1 - } - - pub fn is_root_reference_frame(&self) -> bool { - self.0 == ROOT_REFERENCE_FRAME_SPATIAL_ID - } - - pub fn is_root_scroll_node(&self) -> bool { - self.0 == ROOT_SCROLL_NODE_SPATIAL_ID - } -} - -/// An external identifier that uniquely identifies a scroll frame independent of its ClipId, which -/// may change from frame to frame. This should be unique within a pipeline. WebRender makes no -/// attempt to ensure uniqueness. The zero value is reserved for use by the root scroll node of -/// every pipeline, which always has an external id. -/// -/// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll -/// offsets between different sets of SpatialNodes which are ScrollFrames. -#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] -#[repr(C)] -pub struct ExternalScrollId(pub u64, pub PipelineId); - -impl ExternalScrollId { - pub fn pipeline_id(&self) -> PipelineId { - self.1 - } - - pub fn is_root(&self) -> bool { - self.0 == 0 - } -} - -impl DisplayItem { - pub fn debug_name(&self) -> &'static str { - match *self { - DisplayItem::Border(..) => "border", - DisplayItem::BoxShadow(..) => "box_shadow", - DisplayItem::ClearRectangle(..) => "clear_rectangle", - DisplayItem::HitTest(..) => "hit_test", - DisplayItem::RectClip(..) => "rect_clip", - DisplayItem::RoundedRectClip(..) => "rounded_rect_clip", - DisplayItem::ImageMaskClip(..) => "image_mask_clip", - DisplayItem::Clip(..) => "clip", - DisplayItem::ClipChain(..) => "clip_chain", - DisplayItem::ConicGradient(..) => "conic_gradient", - DisplayItem::Gradient(..) => "gradient", - DisplayItem::Iframe(..) => "iframe", - DisplayItem::Image(..) => "image", - DisplayItem::RepeatingImage(..) => "repeating_image", - DisplayItem::Line(..) => "line", - DisplayItem::PopAllShadows => "pop_all_shadows", - DisplayItem::PopReferenceFrame => "pop_reference_frame", - DisplayItem::PopStackingContext => "pop_stacking_context", - DisplayItem::PushShadow(..) => "push_shadow", - DisplayItem::PushReferenceFrame(..) => "push_reference_frame", - DisplayItem::PushStackingContext(..) => "push_stacking_context", - DisplayItem::SetFilterOps => "set_filter_ops", - DisplayItem::SetFilterData => "set_filter_data", - DisplayItem::SetFilterPrimitives => "set_filter_primitives", - DisplayItem::SetPoints => "set_points", - DisplayItem::RadialGradient(..) => "radial_gradient", - DisplayItem::Rectangle(..) => "rectangle", - DisplayItem::ScrollFrame(..) => "scroll_frame", - DisplayItem::SetGradientStops => "set_gradient_stops", - DisplayItem::ReuseItems(..) => "reuse_item", - DisplayItem::RetainedItems(..) => "retained_items", - DisplayItem::StickyFrame(..) => "sticky_frame", - DisplayItem::Text(..) => "text", - DisplayItem::YuvImage(..) => "yuv_image", - DisplayItem::BackdropFilter(..) => "backdrop_filter", - } - } -} - -macro_rules! impl_default_for_enums { - ($($enum:ident => $init:expr ),+) => { - $(impl Default for $enum { - #[allow(unused_imports)] - fn default() -> Self { - use $enum::*; - $init - } - })* - } -} - -impl_default_for_enums! { - DisplayItem => PopStackingContext, - ScrollSensitivity => ScriptAndInputEvents, - LineOrientation => Vertical, - LineStyle => Solid, - RepeatMode => Stretch, - NinePatchBorderSource => Image(ImageKey::default()), - BorderDetails => Normal(NormalBorder::default()), - BorderRadiusKind => Uniform, - BorderStyle => None, - BoxShadowClipMode => Outset, - ExtendMode => Clamp, - FilterOp => Identity, - ComponentTransferFuncType => Identity, - ClipMode => Clip, - FillRule => Nonzero, - ClipId => ClipId::invalid(), - ReferenceFrameKind => Transform { - is_2d_scale_translation: false, - should_snap: false, - }, - Rotation => Degree0, - TransformStyle => Flat, - RasterSpace => Local(f32::default()), - MixBlendMode => Normal, - ImageRendering => Auto, - AlphaType => Alpha, - YuvColorSpace => Rec601, - ColorRange => Limited, - YuvData => NV12(ImageKey::default(), ImageKey::default()), - YuvFormat => NV12, - FilterPrimitiveInput => Original, - ColorSpace => Srgb, - CompositeOperator => Over -} diff --git a/third_party/webrender/webrender_api/src/display_item_cache.rs b/third_party/webrender/webrender_api/src/display_item_cache.rs deleted file mode 100644 index 8a28ac4ab2c..00000000000 --- a/third_party/webrender/webrender_api/src/display_item_cache.rs +++ /dev/null @@ -1,115 +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 http://mozilla.org/MPL/2.0/. */ - -use crate::display_item::*; -use crate::display_list::*; -use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; - -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct CachedDisplayItem { - item: DisplayItem, - data: Vec<u8>, -} - -impl CachedDisplayItem { - pub fn display_item(&self) -> &DisplayItem { - &self.item - } - - pub fn data_as_item_range<T>(&self) -> ItemRange<T> { - ItemRange::new(&self.data) - } -} - -impl MallocSizeOf for CachedDisplayItem { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.data.size_of(ops) - } -} - -impl From<DisplayItemRef<'_, '_>> for CachedDisplayItem { - fn from(item_ref: DisplayItemRef) -> Self { - let item = item_ref.item(); - - match item { - DisplayItem::Text(..) => CachedDisplayItem { - item: *item, - data: item_ref.glyphs().bytes().to_vec(), - }, - _ => CachedDisplayItem { - item: *item, - data: Vec::new(), - }, - } - } -} - -#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] -struct CacheEntry { - items: Vec<CachedDisplayItem>, - occupied: bool, -} - -#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] -pub struct DisplayItemCache { - entries: Vec<CacheEntry>, -} - -impl DisplayItemCache { - fn add_item(&mut self, key: ItemKey, item: CachedDisplayItem) { - let entry = &mut self.entries[key as usize]; - entry.items.push(item); - entry.occupied = true; - } - - fn clear_entry(&mut self, key: ItemKey) { - let entry = &mut self.entries[key as usize]; - entry.items.clear(); - entry.occupied = false; - } - - fn grow_if_needed(&mut self, capacity: usize) { - if capacity > self.entries.len() { - self.entries.resize_with(capacity, || CacheEntry { - items: Vec::new(), - occupied: false, - }); - } - } - - pub fn get_items(&self, key: ItemKey) -> &[CachedDisplayItem] { - let entry = &self.entries[key as usize]; - debug_assert!(entry.occupied); - entry.items.as_slice() - } - - pub fn new() -> Self { - Self { - entries: Vec::new(), - } - } - - pub fn update(&mut self, display_list: &BuiltDisplayList) { - self.grow_if_needed(display_list.cache_size()); - - let mut iter = display_list.extra_data_iter(); - let mut current_key: Option<ItemKey> = None; - loop { - let item = match iter.next() { - Some(item) => item, - None => break, - }; - - if let DisplayItem::RetainedItems(key) = item.item() { - current_key = Some(*key); - self.clear_entry(*key); - continue; - } - - let key = current_key.expect("Missing RetainedItems marker"); - let cached_item = CachedDisplayItem::from(item); - self.add_item(key, cached_item); - } - } -} diff --git a/third_party/webrender/webrender_api/src/display_list.rs b/third_party/webrender/webrender_api/src/display_list.rs deleted file mode 100644 index e2498c5c194..00000000000 --- a/third_party/webrender/webrender_api/src/display_list.rs +++ /dev/null @@ -1,2057 +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 http://mozilla.org/MPL/2.0/. */ - -use euclid::SideOffsets2D; -use peek_poke::{ensure_red_zone, peek_from_slice, poke_extend_vec, strip_red_zone}; -use peek_poke::{poke_inplace_slice, poke_into_vec, Poke}; -#[cfg(feature = "deserialize")] -use serde::de::Deserializer; -#[cfg(feature = "serialize")] -use serde::ser::{Serializer, SerializeSeq}; -use serde::{Deserialize, Serialize}; -use std::io::Write; -use std::marker::PhantomData; -use std::ops::Range; -use std::mem; -use std::collections::HashMap; -use time::precise_time_ns; -use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -// local imports -use crate::display_item as di; -use crate::display_item_cache::*; -use crate::{PipelineId, PropertyBinding}; -use crate::gradient_builder::GradientBuilder; -use crate::color::ColorF; -use crate::font::{FontInstanceKey, GlyphInstance, GlyphOptions}; -use crate::image::{ColorDepth, ImageKey}; -use crate::units::*; - - -// We don't want to push a long text-run. If a text-run is too long, split it into several parts. -// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_TEXT_RUN) * 2 -pub const MAX_TEXT_RUN_LENGTH: usize = 2040; - -// See ROOT_REFERENCE_FRAME_SPATIAL_ID and ROOT_SCROLL_NODE_SPATIAL_ID -// TODO(mrobinson): It would be a good idea to eliminate the root scroll frame which is only -// used by Servo. -const FIRST_SPATIAL_NODE_INDEX: usize = 2; - -// See ROOT_SCROLL_NODE_SPATIAL_ID -const FIRST_CLIP_NODE_INDEX: usize = 1; - -#[repr(C)] -#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct ItemRange<'a, T> { - bytes: &'a [u8], - _boo: PhantomData<T>, -} - -impl<'a, T> Copy for ItemRange<'a, T> {} -impl<'a, T> Clone for ItemRange<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T> Default for ItemRange<'a, T> { - fn default() -> Self { - ItemRange { - bytes: Default::default(), - _boo: PhantomData, - } - } -} - -impl<'a, T> ItemRange<'a, T> { - pub fn new(bytes: &'a [u8]) -> Self { - Self { - bytes, - _boo: PhantomData - } - } - - pub fn is_empty(&self) -> bool { - // Nothing more than space for a length (0). - self.bytes.len() <= mem::size_of::<usize>() - } - - pub fn bytes(&self) -> &[u8] { - &self.bytes - } -} - -impl<'a, T: Default> ItemRange<'a, T> { - pub fn iter(&self) -> AuxIter<'a, T> { - AuxIter::new(T::default(), self.bytes) - } -} - -impl<'a, T> IntoIterator for ItemRange<'a, T> -where - T: Copy + Default + peek_poke::Peek, -{ - type Item = T; - type IntoIter = AuxIter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -#[derive(Copy, Clone)] -pub struct TempFilterData<'a> { - pub func_types: ItemRange<'a, di::ComponentTransferFuncType>, - pub r_values: ItemRange<'a, f32>, - pub g_values: ItemRange<'a, f32>, - pub b_values: ItemRange<'a, f32>, - pub a_values: ItemRange<'a, f32>, -} - -/// A display list. -#[derive(Clone, Default)] -pub struct BuiltDisplayList { - /// Serde encoded bytes. Mostly DisplayItems, but some mixed in slices. - data: Vec<u8>, - descriptor: BuiltDisplayListDescriptor, -} - -#[repr(C)] -#[derive(Copy, Clone, Deserialize, Serialize)] -pub enum GeckoDisplayListType { - None, - Partial(f64), - Full(f64), -} - -impl Default for GeckoDisplayListType { - fn default() -> Self { GeckoDisplayListType::None } -} - -/// Describes the memory layout of a display list. -/// -/// A display list consists of some number of display list items, followed by a number of display -/// items. -#[repr(C)] -#[derive(Copy, Clone, Default, Deserialize, Serialize)] -pub struct BuiltDisplayListDescriptor { - /// Gecko specific information about the display list. - gecko_display_list_type: GeckoDisplayListType, - /// The first IPC time stamp: before any work has been done - builder_start_time: u64, - /// The second IPC time stamp: after serialization - builder_finish_time: u64, - /// The third IPC time stamp: just before sending - send_start_time: u64, - /// The amount of clipping nodes created while building this display list. - total_clip_nodes: usize, - /// The amount of spatial nodes created while building this display list. - total_spatial_nodes: usize, - /// The size of the cache for this display list. - cache_size: usize, - /// The offset for additional display list data. - extra_data_offset: usize, -} - -#[derive(Clone)] -pub struct DisplayListWithCache { - display_list: BuiltDisplayList, - cache: DisplayItemCache, -} - -impl DisplayListWithCache { - pub fn iter(&self) -> BuiltDisplayListIter { - self.display_list.iter_with_cache(&self.cache) - } - - pub fn new_from_list(display_list: BuiltDisplayList) -> Self { - let mut cache = DisplayItemCache::new(); - cache.update(&display_list); - - DisplayListWithCache { - display_list, - cache - } - } - - pub fn update(&mut self, display_list: BuiltDisplayList) { - self.cache.update(&display_list); - self.display_list = display_list; - } - - pub fn descriptor(&self) -> &BuiltDisplayListDescriptor { - self.display_list.descriptor() - } - - pub fn times(&self) -> (u64, u64, u64) { - self.display_list.times() - } - - pub fn data(&self) -> &[u8] { - self.display_list.data() - } -} - -impl MallocSizeOf for DisplayListWithCache { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.display_list.data.size_of(ops) + self.cache.size_of(ops) - } -} - -#[cfg(feature = "serialize")] -impl Serialize for DisplayListWithCache { - fn serialize<S: Serializer>( - &self, - serializer: S - ) -> Result<S::Ok, S::Error> { - BuiltDisplayList::serialize_with_iterator(serializer, self.iter()) - } -} - -#[cfg(feature = "deserialize")] -impl<'de> Deserialize<'de> for DisplayListWithCache { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - let display_list = BuiltDisplayList::deserialize(deserializer)?; - let cache = DisplayItemCache::new(); - - Ok(DisplayListWithCache { - display_list, - cache, - }) - } -} - -impl BuiltDisplayListDescriptor {} - -pub struct BuiltDisplayListIter<'a> { - list: &'a BuiltDisplayList, - data: &'a [u8], - cache: Option<&'a DisplayItemCache>, - pending_items: std::slice::Iter<'a, CachedDisplayItem>, - cur_cached_item: Option<&'a CachedDisplayItem>, - cur_item: di::DisplayItem, - cur_stops: ItemRange<'a, di::GradientStop>, - cur_glyphs: ItemRange<'a, GlyphInstance>, - cur_filters: ItemRange<'a, di::FilterOp>, - cur_filter_data: Vec<TempFilterData<'a>>, - cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>, - cur_clip_chain_items: ItemRange<'a, di::ClipId>, - cur_complex_clip: ItemRange<'a, di::ComplexClipRegion>, - cur_points: ItemRange<'a, LayoutPoint>, - peeking: Peek, - /// Should just be initialized but never populated in release builds - debug_stats: DebugStats, -} - -/// Internal info used for more detailed analysis of serialized display lists -#[allow(dead_code)] -struct DebugStats { - /// Last address in the buffer we pointed to, for computing serialized sizes - last_addr: usize, - stats: HashMap<&'static str, ItemStats>, -} - -impl DebugStats { - #[cfg(feature = "display_list_stats")] - fn _update_entry(&mut self, name: &'static str, item_count: usize, byte_count: usize) { - let entry = self.stats.entry(name).or_default(); - entry.total_count += item_count; - entry.num_bytes += byte_count; - } - - /// Computes the number of bytes we've processed since we last called - /// this method, so we can compute the serialized size of a display item. - #[cfg(feature = "display_list_stats")] - fn debug_num_bytes(&mut self, data: &[u8]) -> usize { - let old_addr = self.last_addr; - let new_addr = data.as_ptr() as usize; - let delta = new_addr - old_addr; - self.last_addr = new_addr; - - delta - } - - /// Logs stats for the last deserialized display item - #[cfg(feature = "display_list_stats")] - fn log_item(&mut self, data: &[u8], item: &di::DisplayItem) { - let num_bytes = self.debug_num_bytes(data); - self._update_entry(item.debug_name(), 1, num_bytes); - } - - /// Logs the stats for the given serialized slice - #[cfg(feature = "display_list_stats")] - fn log_slice<T: Copy + Default + peek_poke::Peek>( - &mut self, - slice_name: &'static str, - range: &ItemRange<T>, - ) { - // Run this so log_item_stats is accurate, but ignore its result - // because log_slice_stats may be called after multiple slices have been - // processed, and the `range` has everything we need. - self.last_addr = range.bytes.as_ptr() as usize + range.bytes.len(); - - self._update_entry(slice_name, range.iter().len(), range.bytes.len()); - } - - #[cfg(not(feature = "display_list_stats"))] - fn log_slice<T>(&mut self, _slice_name: &str, _range: &ItemRange<T>) { - /* no-op */ - } -} - -/// Stats for an individual item -#[derive(Copy, Clone, Debug, Default)] -pub struct ItemStats { - /// How many instances of this kind of item we deserialized - pub total_count: usize, - /// How many bytes we processed for this kind of item - pub num_bytes: usize, -} - -pub struct DisplayItemRef<'a: 'b, 'b> { - iter: &'b BuiltDisplayListIter<'a>, -} - -// Some of these might just become ItemRanges -impl<'a, 'b> DisplayItemRef<'a, 'b> { - pub fn display_list(&self) -> &BuiltDisplayList { - self.iter.display_list() - } - - // Creates a new iterator where this element's iterator is, to hack around borrowck. - pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> { - self.iter.sub_iter() - } - - pub fn item(&self) -> &di::DisplayItem { - self.iter.current_item() - } - - pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> { - self.iter.cur_clip_chain_items - } - - pub fn complex_clip(&self) -> ItemRange<di::ComplexClipRegion> { - self.iter.cur_complex_clip - } - - pub fn points(&self) -> ItemRange<LayoutPoint> { - self.iter.cur_points - } - - pub fn glyphs(&self) -> ItemRange<GlyphInstance> { - self.iter.glyphs() - } - - pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> { - self.iter.gradient_stops() - } - - pub fn filters(&self) -> ItemRange<di::FilterOp> { - self.iter.cur_filters - } - - pub fn filter_datas(&self) -> &Vec<TempFilterData> { - &self.iter.cur_filter_data - } - - pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> { - self.iter.cur_filter_primitives - } -} - -#[derive(PartialEq)] -enum Peek { - StartPeeking, - IsPeeking, - NotPeeking, -} - -#[derive(Clone)] -pub struct AuxIter<'a, T> { - item: T, - data: &'a [u8], - size: usize, -// _boo: PhantomData<T>, -} - -impl BuiltDisplayList { - pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> Self { - BuiltDisplayList { data, descriptor } - } - - pub fn into_data(self) -> (Vec<u8>, BuiltDisplayListDescriptor) { - (self.data, self.descriptor) - } - - pub fn data(&self) -> &[u8] { - &self.data[..] - } - - pub fn item_slice(&self) -> &[u8] { - &self.data[..self.descriptor.extra_data_offset] - } - - pub fn extra_slice(&self) -> &[u8] { - &self.data[self.descriptor.extra_data_offset..] - } - - pub fn descriptor(&self) -> &BuiltDisplayListDescriptor { - &self.descriptor - } - - pub fn set_send_time_ns(&mut self, time: u64) { - self.descriptor.send_start_time = time; - } - - pub fn times(&self) -> (u64, u64, u64) { - ( - self.descriptor.builder_start_time, - self.descriptor.builder_finish_time, - self.descriptor.send_start_time, - ) - } - - pub fn gecko_display_list_stats(&self) -> (f64, bool) { - match self.descriptor.gecko_display_list_type { - GeckoDisplayListType::Full(duration) => (duration, true), - GeckoDisplayListType::Partial(duration) => (duration, false), - _ => (0.0, false) - } - } - - pub fn total_clip_nodes(&self) -> usize { - self.descriptor.total_clip_nodes - } - - pub fn total_spatial_nodes(&self) -> usize { - self.descriptor.total_spatial_nodes - } - - pub fn iter(&self) -> BuiltDisplayListIter { - BuiltDisplayListIter::new(self, self.item_slice(), None) - } - - pub fn extra_data_iter(&self) -> BuiltDisplayListIter { - BuiltDisplayListIter::new(self, self.extra_slice(), None) - } - - pub fn iter_with_cache<'a>( - &'a self, - cache: &'a DisplayItemCache - ) -> BuiltDisplayListIter<'a> { - BuiltDisplayListIter::new(self, self.item_slice(), Some(cache)) - } - - pub fn cache_size(&self) -> usize { - self.descriptor.cache_size - } - - #[cfg(feature = "serialize")] - pub fn serialize_with_iterator<S: Serializer>( - serializer: S, - mut iterator: BuiltDisplayListIter, - ) -> Result<S::Ok, S::Error> { - use crate::display_item::DisplayItem as Real; - use crate::display_item::DebugDisplayItem as Debug; - - let mut seq = serializer.serialize_seq(None)?; - - while let Some(item) = iterator.next_raw() { - let serial_di = match *item.item() { - Real::Clip(v) => Debug::Clip( - v, - item.iter.cur_complex_clip.iter().collect() - ), - Real::ClipChain(v) => Debug::ClipChain( - v, - item.iter.cur_clip_chain_items.iter().collect() - ), - Real::ScrollFrame(v) => Debug::ScrollFrame(v), - Real::Text(v) => Debug::Text( - v, - item.iter.cur_glyphs.iter().collect() - ), - Real::SetFilterOps => Debug::SetFilterOps( - item.iter.cur_filters.iter().collect() - ), - Real::SetFilterData => { - debug_assert!(!item.iter.cur_filter_data.is_empty(), - "next_raw should have populated cur_filter_data"); - let temp_filter_data = &item.iter.cur_filter_data[item.iter.cur_filter_data.len()-1]; - - let func_types: Vec<di::ComponentTransferFuncType> = - temp_filter_data.func_types.iter().collect(); - debug_assert!(func_types.len() == 4, - "someone changed the number of filter funcs without updating this code"); - Debug::SetFilterData(di::FilterData { - func_r_type: func_types[0], - r_values: temp_filter_data.r_values.iter().collect(), - func_g_type: func_types[1], - g_values: temp_filter_data.g_values.iter().collect(), - func_b_type: func_types[2], - b_values: temp_filter_data.b_values.iter().collect(), - func_a_type: func_types[3], - a_values: temp_filter_data.a_values.iter().collect(), - }) - }, - Real::SetFilterPrimitives => Debug::SetFilterPrimitives( - item.iter.cur_filter_primitives.iter().collect() - ), - Real::SetGradientStops => Debug::SetGradientStops( - item.iter.cur_stops.iter().collect() - ), - Real::SetPoints => Debug::SetPoints( - item.iter.cur_points.iter().collect() - ), - Real::RectClip(v) => Debug::RectClip(v), - Real::RoundedRectClip(v) => Debug::RoundedRectClip(v), - Real::ImageMaskClip(v) => Debug::ImageMaskClip(v), - Real::StickyFrame(v) => Debug::StickyFrame(v), - Real::Rectangle(v) => Debug::Rectangle(v), - Real::ClearRectangle(v) => Debug::ClearRectangle(v), - Real::HitTest(v) => Debug::HitTest(v), - Real::Line(v) => Debug::Line(v), - Real::Image(v) => Debug::Image(v), - Real::RepeatingImage(v) => Debug::RepeatingImage(v), - Real::YuvImage(v) => Debug::YuvImage(v), - Real::Border(v) => Debug::Border(v), - Real::BoxShadow(v) => Debug::BoxShadow(v), - Real::Gradient(v) => Debug::Gradient(v), - Real::RadialGradient(v) => Debug::RadialGradient(v), - Real::ConicGradient(v) => Debug::ConicGradient(v), - Real::Iframe(v) => Debug::Iframe(v), - Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v), - Real::PushStackingContext(v) => Debug::PushStackingContext(v), - Real::PushShadow(v) => Debug::PushShadow(v), - Real::BackdropFilter(v) => Debug::BackdropFilter(v), - - Real::PopReferenceFrame => Debug::PopReferenceFrame, - Real::PopStackingContext => Debug::PopStackingContext, - Real::PopAllShadows => Debug::PopAllShadows, - Real::ReuseItems(_) | - Real::RetainedItems(_) => unreachable!("Unexpected item"), - }; - seq.serialize_element(&serial_di)? - } - seq.end() - } -} - -/// Returns the byte-range the slice occupied. -fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> { - let mut skip_offset = 0usize; - *data = peek_from_slice(data, &mut skip_offset); - let (skip, rest) = data.split_at(skip_offset); - - // Adjust data pointer to skip read values - *data = rest; - - ItemRange { - bytes: skip, - _boo: PhantomData, - } -} - -impl<'a> BuiltDisplayListIter<'a> { - pub fn new( - list: &'a BuiltDisplayList, - data: &'a [u8], - cache: Option<&'a DisplayItemCache>, - ) -> Self { - Self { - list, - data, - cache, - pending_items: [].iter(), - cur_cached_item: None, - cur_item: di::DisplayItem::PopStackingContext, - cur_stops: ItemRange::default(), - cur_glyphs: ItemRange::default(), - cur_filters: ItemRange::default(), - cur_filter_data: Vec::new(), - cur_filter_primitives: ItemRange::default(), - cur_clip_chain_items: ItemRange::default(), - cur_complex_clip: ItemRange::default(), - cur_points: ItemRange::default(), - peeking: Peek::NotPeeking, - debug_stats: DebugStats { - last_addr: data.as_ptr() as usize, - stats: HashMap::default(), - }, - } - } - - pub fn sub_iter(&self) -> Self { - let mut iter = BuiltDisplayListIter::new( - self.list, self.data, self.cache - ); - iter.pending_items = self.pending_items.clone(); - iter - } - - pub fn display_list(&self) -> &'a BuiltDisplayList { - self.list - } - - pub fn current_item(&self) -> &di::DisplayItem { - match self.cur_cached_item { - Some(cached_item) => cached_item.display_item(), - None => &self.cur_item - } - } - - fn cached_item_range_or<T>( - &self, - data: ItemRange<'a, T> - ) -> ItemRange<'a, T> { - match self.cur_cached_item { - Some(cached_item) => cached_item.data_as_item_range(), - None => data, - } - } - - pub fn glyphs(&self) -> ItemRange<GlyphInstance> { - self.cached_item_range_or(self.cur_glyphs) - } - - pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> { - self.cached_item_range_or(self.cur_stops) - } - - fn advance_pending_items(&mut self) -> bool { - self.cur_cached_item = self.pending_items.next(); - self.cur_cached_item.is_some() - } - - pub fn next<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> { - use crate::DisplayItem::*; - - match self.peeking { - Peek::IsPeeking => { - self.peeking = Peek::NotPeeking; - return Some(self.as_ref()); - } - Peek::StartPeeking => { - self.peeking = Peek::IsPeeking; - } - Peek::NotPeeking => { /* do nothing */ } - } - - // Don't let these bleed into another item - self.cur_stops = ItemRange::default(); - self.cur_complex_clip = ItemRange::default(); - self.cur_clip_chain_items = ItemRange::default(); - self.cur_points = ItemRange::default(); - self.cur_filters = ItemRange::default(); - self.cur_filter_primitives = ItemRange::default(); - self.cur_filter_data.clear(); - - loop { - self.next_raw()?; - match self.cur_item { - SetGradientStops | - SetFilterOps | - SetFilterData | - SetFilterPrimitives | - SetPoints => { - // These are marker items for populating other display items, don't yield them. - continue; - } - _ => { - break; - } - } - } - - Some(self.as_ref()) - } - - /// Gets the next display item, even if it's a dummy. Also doesn't handle peeking - /// and may leave irrelevant ranges live (so a Clip may have GradientStops if - /// for some reason you ask). - pub fn next_raw<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> { - use crate::DisplayItem::*; - - if self.advance_pending_items() { - return Some(self.as_ref()); - } - - // A "red zone" of DisplayItem::max_size() bytes has been added to the - // end of the serialized display list. If this amount, or less, is - // remaining then we've reached the end of the display list. - if self.data.len() <= di::DisplayItem::max_size() { - return None; - } - - self.data = peek_from_slice(self.data, &mut self.cur_item); - self.log_item_stats(); - - match self.cur_item { - SetGradientStops => { - self.cur_stops = skip_slice::<di::GradientStop>(&mut self.data); - self.debug_stats.log_slice("set_gradient_stops.stops", &self.cur_stops); - } - SetFilterOps => { - self.cur_filters = skip_slice::<di::FilterOp>(&mut self.data); - self.debug_stats.log_slice("set_filter_ops.ops", &self.cur_filters); - } - SetFilterData => { - self.cur_filter_data.push(TempFilterData { - func_types: skip_slice::<di::ComponentTransferFuncType>(&mut self.data), - r_values: skip_slice::<f32>(&mut self.data), - g_values: skip_slice::<f32>(&mut self.data), - b_values: skip_slice::<f32>(&mut self.data), - a_values: skip_slice::<f32>(&mut self.data), - }); - - let data = *self.cur_filter_data.last().unwrap(); - self.debug_stats.log_slice("set_filter_data.func_types", &data.func_types); - self.debug_stats.log_slice("set_filter_data.r_values", &data.r_values); - self.debug_stats.log_slice("set_filter_data.g_values", &data.g_values); - self.debug_stats.log_slice("set_filter_data.b_values", &data.b_values); - self.debug_stats.log_slice("set_filter_data.a_values", &data.a_values); - } - SetFilterPrimitives => { - self.cur_filter_primitives = skip_slice::<di::FilterPrimitive>(&mut self.data); - self.debug_stats.log_slice("set_filter_primitives.primitives", &self.cur_filter_primitives); - } - SetPoints => { - self.cur_points = skip_slice::<LayoutPoint>(&mut self.data); - self.debug_stats.log_slice("set_points.points", &self.cur_points); - } - ClipChain(_) => { - self.cur_clip_chain_items = skip_slice::<di::ClipId>(&mut self.data); - self.debug_stats.log_slice("clip_chain.clip_ids", &self.cur_clip_chain_items); - } - Clip(_) => { - self.cur_complex_clip = skip_slice::<di::ComplexClipRegion>(&mut self.data); - self.debug_stats.log_slice("clip.complex_clips", &self.cur_complex_clip); - } - Text(_) => { - self.cur_glyphs = skip_slice::<GlyphInstance>(&mut self.data); - self.debug_stats.log_slice("text.glyphs", &self.cur_glyphs); - } - ReuseItems(key) => { - match self.cache { - Some(cache) => { - self.pending_items = cache.get_items(key).iter(); - self.advance_pending_items(); - } - None => { - unreachable!("Cache marker without cache!"); - } - } - } - _ => { /* do nothing */ } - } - - Some(self.as_ref()) - } - - pub fn as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b> { - DisplayItemRef { - iter: self, - } - } - - pub fn skip_current_stacking_context(&mut self) { - let mut depth = 0; - while let Some(item) = self.next() { - match *item.item() { - di::DisplayItem::PushStackingContext(..) => depth += 1, - di::DisplayItem::PopStackingContext if depth == 0 => return, - di::DisplayItem::PopStackingContext => depth -= 1, - _ => {} - } - } - } - - pub fn current_stacking_context_empty(&mut self) -> bool { - match self.peek() { - Some(item) => *item.item() == di::DisplayItem::PopStackingContext, - None => true, - } - } - - pub fn peek<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> { - if self.peeking == Peek::NotPeeking { - self.peeking = Peek::StartPeeking; - self.next() - } else { - Some(self.as_ref()) - } - } - - /// Get the debug stats for what this iterator has deserialized. - /// Should always be empty in release builds. - pub fn debug_stats(&mut self) -> Vec<(&'static str, ItemStats)> { - let mut result = self.debug_stats.stats.drain().collect::<Vec<_>>(); - result.sort_by_key(|stats| stats.0); - result - } - - /// Adds the debug stats from another to our own, assuming we are a sub-iter of the other - /// (so we can ignore where they were in the traversal). - pub fn merge_debug_stats_from(&mut self, other: &mut Self) { - for (key, other_entry) in other.debug_stats.stats.iter() { - let entry = self.debug_stats.stats.entry(key).or_default(); - - entry.total_count += other_entry.total_count; - entry.num_bytes += other_entry.num_bytes; - } - } - - /// Logs stats for the last deserialized display item - #[cfg(feature = "display_list_stats")] - fn log_item_stats(&mut self) { - self.debug_stats.log_item(self.data, &self.cur_item); - } - - #[cfg(not(feature = "display_list_stats"))] - fn log_item_stats(&mut self) { /* no-op */ } -} - -impl<'a, T> AuxIter<'a, T> { - pub fn new(item: T, mut data: &'a [u8]) -> Self { - let mut size = 0usize; - if !data.is_empty() { - data = peek_from_slice(data, &mut size); - }; - - AuxIter { - item, - data, - size, -// _boo: PhantomData, - } - } -} - -impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option<Self::Item> { - if self.size == 0 { - None - } else { - self.size -= 1; - self.data = peek_from_slice(self.data, &mut self.item); - Some(self.item) - } - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.size, Some(self.size)) - } -} - -impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {} - -#[cfg(feature = "serialize")] -impl Serialize for BuiltDisplayList { - fn serialize<S: Serializer>( - &self, - serializer: S - ) -> Result<S::Ok, S::Error> { - Self::serialize_with_iterator(serializer, self.iter()) - } -} - -// The purpose of this implementation is to deserialize -// a display list from one format just to immediately -// serialize then into a "built" `Vec<u8>`. - -#[cfg(feature = "deserialize")] -impl<'de> Deserialize<'de> for BuiltDisplayList { - fn deserialize<D: Deserializer<'de>>( - deserializer: D - ) -> Result<Self, D::Error> { - use crate::display_item::DisplayItem as Real; - use crate::display_item::DebugDisplayItem as Debug; - - let list = Vec::<Debug>::deserialize(deserializer)?; - - let mut data = Vec::new(); - let mut temp = Vec::new(); - let mut total_clip_nodes = FIRST_CLIP_NODE_INDEX; - let mut total_spatial_nodes = FIRST_SPATIAL_NODE_INDEX; - for complete in list { - let item = match complete { - Debug::Clip(v, complex_clips) => { - total_clip_nodes += 1; - DisplayListBuilder::push_iter_impl(&mut temp, complex_clips); - Real::Clip(v) - }, - Debug::ClipChain(v, clip_chain_ids) => { - DisplayListBuilder::push_iter_impl(&mut temp, clip_chain_ids); - Real::ClipChain(v) - } - Debug::ScrollFrame(v) => { - total_spatial_nodes += 1; - total_clip_nodes += 1; - Real::ScrollFrame(v) - } - Debug::StickyFrame(v) => { - total_spatial_nodes += 1; - Real::StickyFrame(v) - } - Debug::Text(v, glyphs) => { - DisplayListBuilder::push_iter_impl(&mut temp, glyphs); - Real::Text(v) - }, - Debug::Iframe(v) => { - total_clip_nodes += 1; - Real::Iframe(v) - } - Debug::PushReferenceFrame(v) => { - total_spatial_nodes += 1; - Real::PushReferenceFrame(v) - } - Debug::SetFilterOps(filters) => { - DisplayListBuilder::push_iter_impl(&mut temp, filters); - Real::SetFilterOps - }, - Debug::SetFilterData(filter_data) => { - let func_types: Vec<di::ComponentTransferFuncType> = - [filter_data.func_r_type, - filter_data.func_g_type, - filter_data.func_b_type, - filter_data.func_a_type].to_vec(); - DisplayListBuilder::push_iter_impl(&mut temp, func_types); - DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values); - DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values); - DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values); - DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values); - Real::SetFilterData - }, - Debug::SetFilterPrimitives(filter_primitives) => { - DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives); - Real::SetFilterPrimitives - } - Debug::SetGradientStops(stops) => { - DisplayListBuilder::push_iter_impl(&mut temp, stops); - Real::SetGradientStops - }, - Debug::SetPoints(points) => { - DisplayListBuilder::push_iter_impl(&mut temp, points); - Real::SetPoints - }, - Debug::RectClip(v) => Real::RectClip(v), - Debug::RoundedRectClip(v) => Real::RoundedRectClip(v), - Debug::ImageMaskClip(v) => Real::ImageMaskClip(v), - Debug::Rectangle(v) => Real::Rectangle(v), - Debug::ClearRectangle(v) => Real::ClearRectangle(v), - Debug::HitTest(v) => Real::HitTest(v), - Debug::Line(v) => Real::Line(v), - Debug::Image(v) => Real::Image(v), - Debug::RepeatingImage(v) => Real::RepeatingImage(v), - Debug::YuvImage(v) => Real::YuvImage(v), - Debug::Border(v) => Real::Border(v), - Debug::BoxShadow(v) => Real::BoxShadow(v), - Debug::Gradient(v) => Real::Gradient(v), - Debug::RadialGradient(v) => Real::RadialGradient(v), - Debug::ConicGradient(v) => Real::ConicGradient(v), - Debug::PushStackingContext(v) => Real::PushStackingContext(v), - Debug::PushShadow(v) => Real::PushShadow(v), - Debug::BackdropFilter(v) => Real::BackdropFilter(v), - - Debug::PopStackingContext => Real::PopStackingContext, - Debug::PopReferenceFrame => Real::PopReferenceFrame, - Debug::PopAllShadows => Real::PopAllShadows, - }; - poke_into_vec(&item, &mut data); - // the aux data is serialized after the item, hence the temporary - data.extend(temp.drain(..)); - } - - // Add `DisplayItem::max_size` zone of zeroes to the end of display list - // so there is at least this amount available in the display list during - // serialization. - ensure_red_zone::<di::DisplayItem>(&mut data); - let extra_data_offset = data.len(); - - Ok(BuiltDisplayList { - data, - descriptor: BuiltDisplayListDescriptor { - gecko_display_list_type: GeckoDisplayListType::None, - builder_start_time: 0, - builder_finish_time: 1, - send_start_time: 1, - total_clip_nodes, - total_spatial_nodes, - extra_data_offset, - cache_size: 0, - }, - }) - } -} - -#[derive(Clone, Debug)] -pub struct SaveState { - dl_len: usize, - next_clip_index: usize, - next_spatial_index: usize, - next_clip_chain_id: u64, -} - -/// DisplayListSection determines the target buffer for the display items. -pub enum DisplayListSection { - /// The main/default buffer: contains item data and item group markers. - Data, - /// Auxiliary buffer: contains the item data for item groups. - ExtraData, - /// Temporary buffer: contains the data for pending item group. Flushed to - /// one of the buffers above, after item grouping finishes. - Chunk, -} - -#[derive(Clone)] -pub struct DisplayListBuilder { - pub data: Vec<u8>, - pub pipeline_id: PipelineId, - - extra_data: Vec<u8>, - pending_chunk: Vec<u8>, - writing_to_chunk: bool, - - next_clip_index: usize, - next_spatial_index: usize, - next_clip_chain_id: u64, - builder_start_time: u64, - - save_state: Option<SaveState>, - - cache_size: usize, - serialized_content_buffer: Option<String>, -} - -impl DisplayListBuilder { - pub fn new(pipeline_id: PipelineId) -> Self { - Self::with_capacity(pipeline_id, 0) - } - - pub fn with_capacity( - pipeline_id: PipelineId, - capacity: usize, - ) -> Self { - let start_time = precise_time_ns(); - - DisplayListBuilder { - data: Vec::with_capacity(capacity), - pipeline_id, - - extra_data: Vec::new(), - pending_chunk: Vec::new(), - writing_to_chunk: false, - - next_clip_index: FIRST_CLIP_NODE_INDEX, - next_spatial_index: FIRST_SPATIAL_NODE_INDEX, - next_clip_chain_id: 0, - builder_start_time: start_time, - save_state: None, - cache_size: 0, - serialized_content_buffer: None, - } - } - - /// Saves the current display list state, so it may be `restore()`'d. - /// - /// # Conditions: - /// - /// * Doesn't support popping clips that were pushed before the save. - /// * Doesn't support nested saves. - /// * Must call `clear_save()` if the restore becomes unnecessary. - pub fn save(&mut self) { - assert!(self.save_state.is_none(), "DisplayListBuilder doesn't support nested saves"); - - self.save_state = Some(SaveState { - dl_len: self.data.len(), - next_clip_index: self.next_clip_index, - next_spatial_index: self.next_spatial_index, - next_clip_chain_id: self.next_clip_chain_id, - }); - } - - /// Restores the state of the builder to when `save()` was last called. - pub fn restore(&mut self) { - let state = self.save_state.take().expect("No save to restore DisplayListBuilder from"); - - self.data.truncate(state.dl_len); - self.next_clip_index = state.next_clip_index; - self.next_spatial_index = state.next_spatial_index; - self.next_clip_chain_id = state.next_clip_chain_id; - } - - /// Discards the builder's save (indicating the attempted operation was successful). - pub fn clear_save(&mut self) { - self.save_state.take().expect("No save to clear in DisplayListBuilder"); - } - - /// Emits a debug representation of display items in the list, for debugging - /// purposes. If the range's start parameter is specified, only display - /// items starting at that index (inclusive) will be printed. If the range's - /// end parameter is specified, only display items before that index - /// (exclusive) will be printed. Calling this function with end <= start is - /// allowed but is just a waste of CPU cycles. The function emits the - /// debug representation of the selected display items, one per line, with - /// the given indent, to the provided sink object. The return value is - /// the total number of items in the display list, which allows the - /// caller to subsequently invoke this function to only dump the newly-added - /// items. - pub fn emit_display_list<W>( - &mut self, - indent: usize, - range: Range<Option<usize>>, - mut sink: W, - ) -> usize - where - W: Write - { - let mut temp = BuiltDisplayList::default(); - ensure_red_zone::<di::DisplayItem>(&mut self.data); - temp.descriptor.extra_data_offset = self.data.len(); - mem::swap(&mut temp.data, &mut self.data); - - let mut index: usize = 0; - { - let mut cache = DisplayItemCache::new(); - cache.update(&temp); - let mut iter = temp.iter_with_cache(&cache); - while let Some(item) = iter.next_raw() { - if index >= range.start.unwrap_or(0) && range.end.map_or(true, |e| index < e) { - writeln!(sink, "{}{:?}", " ".repeat(indent), item.item()).unwrap(); - } - index += 1; - } - } - - self.data = temp.data; - strip_red_zone::<di::DisplayItem>(&mut self.data); - index - } - - /// Print the display items in the list to stdout. - pub fn dump_serialized_display_list(&mut self) { - self.serialized_content_buffer = Some(String::new()); - } - - fn add_to_display_list_dump<T: std::fmt::Debug>(&mut self, item: T) { - if let Some(ref mut content) = self.serialized_content_buffer { - use std::fmt::Write; - write!(content, "{:?}\n", item).expect("DL dump write failed."); - } - } - - /// Returns the default section that DisplayListBuilder will write to, - /// if no section is specified explicitly. - fn default_section(&self) -> DisplayListSection { - if self.writing_to_chunk { - DisplayListSection::Chunk - } else { - DisplayListSection::Data - } - } - - fn buffer_from_section( - &mut self, - section: DisplayListSection - ) -> &mut Vec<u8> { - match section { - DisplayListSection::Data => &mut self.data, - DisplayListSection::ExtraData => &mut self.extra_data, - DisplayListSection::Chunk => &mut self.pending_chunk, - } - } - - #[inline] - pub fn push_item_to_section( - &mut self, - item: &di::DisplayItem, - section: DisplayListSection, - ) { - poke_into_vec(item, self.buffer_from_section(section)); - self.add_to_display_list_dump(item); - } - - /// Add an item to the display list. - /// - /// NOTE: It is usually preferable to use the specialized methods to push - /// display items. Pushing unexpected or invalid items here may - /// result in WebRender panicking or behaving in unexpected ways. - #[inline] - pub fn push_item(&mut self, item: &di::DisplayItem) { - self.push_item_to_section(item, self.default_section()); - } - - fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I) - where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, - I::Item: Poke, - { - let iter = iter_source.into_iter(); - let len = iter.len(); - // Format: - // payload_byte_size: usize, item_count: usize, [I; item_count] - - // Track the the location of where to write byte size with offsets - // instead of pointers because data may be moved in memory during - // `serialize_iter_fast`. - let byte_size_offset = data.len(); - - // We write a dummy value so there's room for later - poke_into_vec(&0usize, data); - poke_into_vec(&len, data); - let count = poke_extend_vec(iter, data); - debug_assert_eq!(len, count, "iterator.len() returned two different values"); - - // Add red zone - ensure_red_zone::<I::Item>(data); - - // Now write the actual byte_size - let final_offset = data.len(); - debug_assert!(final_offset >= (byte_size_offset + mem::size_of::<usize>()), - "space was never allocated for this array's byte_size"); - let byte_size = final_offset - byte_size_offset - mem::size_of::<usize>(); - poke_inplace_slice(&byte_size, &mut data[byte_size_offset..]); - } - - /// Push items from an iterator to the display list. - /// - /// NOTE: Pushing unexpected or invalid items to the display list - /// may result in panic and confusion. - pub fn push_iter<I>(&mut self, iter: I) - where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, - I::Item: Poke, - { - let mut buffer = self.buffer_from_section(self.default_section()); - Self::push_iter_impl(&mut buffer, iter); - } - - pub fn push_rect( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - color: ColorF, - ) { - let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem { - common: *common, - color: PropertyBinding::Value(color), - bounds, - }); - self.push_item(&item); - } - - pub fn push_rect_with_animation( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - color: PropertyBinding<ColorF>, - ) { - let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem { - common: *common, - color, - bounds, - }); - self.push_item(&item); - } - - pub fn push_clear_rect( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - ) { - let item = di::DisplayItem::ClearRectangle(di::ClearRectangleDisplayItem { - common: *common, - bounds, - }); - self.push_item(&item); - } - - pub fn push_hit_test( - &mut self, - common: &di::CommonItemProperties, - tag: di::ItemTag, - ) { - let item = di::DisplayItem::HitTest(di::HitTestDisplayItem { - common: *common, - tag, - }); - self.push_item(&item); - } - - pub fn push_line( - &mut self, - common: &di::CommonItemProperties, - area: &LayoutRect, - wavy_line_thickness: f32, - orientation: di::LineOrientation, - color: &ColorF, - style: di::LineStyle, - ) { - let item = di::DisplayItem::Line(di::LineDisplayItem { - common: *common, - area: *area, - wavy_line_thickness, - orientation, - color: *color, - style, - }); - - self.push_item(&item); - } - - pub fn push_image( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - image_rendering: di::ImageRendering, - alpha_type: di::AlphaType, - key: ImageKey, - color: ColorF, - ) { - let item = di::DisplayItem::Image(di::ImageDisplayItem { - common: *common, - bounds, - image_key: key, - image_rendering, - alpha_type, - color, - }); - - self.push_item(&item); - } - - pub fn push_repeating_image( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - stretch_size: LayoutSize, - tile_spacing: LayoutSize, - image_rendering: di::ImageRendering, - alpha_type: di::AlphaType, - key: ImageKey, - color: ColorF, - ) { - let item = di::DisplayItem::RepeatingImage(di::RepeatingImageDisplayItem { - common: *common, - bounds, - image_key: key, - stretch_size, - tile_spacing, - image_rendering, - alpha_type, - color, - }); - - self.push_item(&item); - } - - /// Push a yuv image. All planar data in yuv image should use the same buffer type. - pub fn push_yuv_image( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - yuv_data: di::YuvData, - color_depth: ColorDepth, - color_space: di::YuvColorSpace, - color_range: di::ColorRange, - image_rendering: di::ImageRendering, - ) { - let item = di::DisplayItem::YuvImage(di::YuvImageDisplayItem { - common: *common, - bounds, - yuv_data, - color_depth, - color_space, - color_range, - image_rendering, - }); - self.push_item(&item); - } - - pub fn push_text( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - glyphs: &[GlyphInstance], - font_key: FontInstanceKey, - color: ColorF, - glyph_options: Option<GlyphOptions>, - ) { - let item = di::DisplayItem::Text(di::TextDisplayItem { - common: *common, - bounds, - color, - font_key, - glyph_options, - }); - - for split_glyphs in glyphs.chunks(MAX_TEXT_RUN_LENGTH) { - self.push_item(&item); - self.push_iter(split_glyphs); - } - } - - /// NOTE: gradients must be pushed in the order they're created - /// because create_gradient stores the stops in anticipation. - pub fn create_gradient( - &mut self, - start_point: LayoutPoint, - end_point: LayoutPoint, - stops: Vec<di::GradientStop>, - extend_mode: di::ExtendMode, - ) -> di::Gradient { - let mut builder = GradientBuilder::with_stops(stops); - let gradient = builder.gradient(start_point, end_point, extend_mode); - self.push_stops(builder.stops()); - gradient - } - - /// NOTE: gradients must be pushed in the order they're created - /// because create_gradient stores the stops in anticipation. - pub fn create_radial_gradient( - &mut self, - center: LayoutPoint, - radius: LayoutSize, - stops: Vec<di::GradientStop>, - extend_mode: di::ExtendMode, - ) -> di::RadialGradient { - let mut builder = GradientBuilder::with_stops(stops); - let gradient = builder.radial_gradient(center, radius, extend_mode); - self.push_stops(builder.stops()); - gradient - } - - /// NOTE: gradients must be pushed in the order they're created - /// because create_gradient stores the stops in anticipation. - pub fn create_conic_gradient( - &mut self, - center: LayoutPoint, - angle: f32, - stops: Vec<di::GradientStop>, - extend_mode: di::ExtendMode, - ) -> di::ConicGradient { - let mut builder = GradientBuilder::with_stops(stops); - let gradient = builder.conic_gradient(center, angle, extend_mode); - self.push_stops(builder.stops()); - gradient - } - - pub fn push_border( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - widths: LayoutSideOffsets, - details: di::BorderDetails, - ) { - let item = di::DisplayItem::Border(di::BorderDisplayItem { - common: *common, - bounds, - details, - widths, - }); - - self.push_item(&item); - } - - pub fn push_box_shadow( - &mut self, - common: &di::CommonItemProperties, - box_bounds: LayoutRect, - offset: LayoutVector2D, - color: ColorF, - blur_radius: f32, - spread_radius: f32, - border_radius: di::BorderRadius, - clip_mode: di::BoxShadowClipMode, - ) { - let item = di::DisplayItem::BoxShadow(di::BoxShadowDisplayItem { - common: *common, - box_bounds, - offset, - color, - blur_radius, - spread_radius, - border_radius, - clip_mode, - }); - - self.push_item(&item); - } - - /// Pushes a linear gradient to be displayed. - /// - /// The gradient itself is described in the - /// `gradient` parameter. It is drawn on - /// a "tile" with the dimensions from `tile_size`. - /// These tiles are now repeated to the right and - /// to the bottom infinitely. If `tile_spacing` - /// is not zero spacers with the given dimensions - /// are inserted between the tiles as seams. - /// - /// The origin of the tiles is given in `layout.rect.origin`. - /// If the gradient should only be displayed once limit - /// the `layout.rect.size` to a single tile. - /// The gradient is only visible within the local clip. - pub fn push_gradient( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - gradient: di::Gradient, - tile_size: LayoutSize, - tile_spacing: LayoutSize, - ) { - let item = di::DisplayItem::Gradient(di::GradientDisplayItem { - common: *common, - bounds, - gradient, - tile_size, - tile_spacing, - }); - - self.push_item(&item); - } - - /// Pushes a radial gradient to be displayed. - /// - /// See [`push_gradient`](#method.push_gradient) for explanation. - pub fn push_radial_gradient( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - gradient: di::RadialGradient, - tile_size: LayoutSize, - tile_spacing: LayoutSize, - ) { - let item = di::DisplayItem::RadialGradient(di::RadialGradientDisplayItem { - common: *common, - bounds, - gradient, - tile_size, - tile_spacing, - }); - - self.push_item(&item); - } - - /// Pushes a conic gradient to be displayed. - /// - /// See [`push_gradient`](#method.push_gradient) for explanation. - pub fn push_conic_gradient( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - gradient: di::ConicGradient, - tile_size: LayoutSize, - tile_spacing: LayoutSize, - ) { - let item = di::DisplayItem::ConicGradient(di::ConicGradientDisplayItem { - common: *common, - bounds, - gradient, - tile_size, - tile_spacing, - }); - - self.push_item(&item); - } - - pub fn push_reference_frame( - &mut self, - origin: LayoutPoint, - parent_spatial_id: di::SpatialId, - transform_style: di::TransformStyle, - transform: PropertyBinding<LayoutTransform>, - kind: di::ReferenceFrameKind, - ) -> di::SpatialId { - let id = self.generate_spatial_index(); - - let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem { - parent_spatial_id, - origin, - reference_frame: di::ReferenceFrame { - transform_style, - transform: di::ReferenceTransformBinding::Static { - binding: transform, - }, - kind, - id, - }, - }); - - self.push_item(&item); - id - } - - pub fn push_computed_frame( - &mut self, - origin: LayoutPoint, - parent_spatial_id: di::SpatialId, - scale_from: Option<LayoutSize>, - vertical_flip: bool, - rotation: di::Rotation, - ) -> di::SpatialId { - let id = self.generate_spatial_index(); - - let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem { - parent_spatial_id, - origin, - reference_frame: di::ReferenceFrame { - transform_style: di::TransformStyle::Flat, - transform: di::ReferenceTransformBinding::Computed { - scale_from, - vertical_flip, - rotation, - }, - kind: di::ReferenceFrameKind::Transform { - is_2d_scale_translation: false, - should_snap: false, - }, - id, - }, - }); - - self.push_item(&item); - id - } - - pub fn pop_reference_frame(&mut self) { - self.push_item(&di::DisplayItem::PopReferenceFrame); - } - - pub fn push_stacking_context( - &mut self, - origin: LayoutPoint, - spatial_id: di::SpatialId, - prim_flags: di::PrimitiveFlags, - clip_id: Option<di::ClipId>, - transform_style: di::TransformStyle, - mix_blend_mode: di::MixBlendMode, - filters: &[di::FilterOp], - filter_datas: &[di::FilterData], - filter_primitives: &[di::FilterPrimitive], - raster_space: di::RasterSpace, - flags: di::StackingContextFlags, - ) { - self.push_filters(filters, filter_datas, filter_primitives); - - let item = di::DisplayItem::PushStackingContext(di::PushStackingContextDisplayItem { - origin, - spatial_id, - prim_flags, - stacking_context: di::StackingContext { - transform_style, - mix_blend_mode, - clip_id, - raster_space, - flags, - }, - }); - - self.push_item(&item); - } - - /// Helper for examples/ code. - pub fn push_simple_stacking_context( - &mut self, - origin: LayoutPoint, - spatial_id: di::SpatialId, - prim_flags: di::PrimitiveFlags, - ) { - self.push_simple_stacking_context_with_filters( - origin, - spatial_id, - prim_flags, - &[], - &[], - &[], - ); - } - - /// Helper for examples/ code. - pub fn push_simple_stacking_context_with_filters( - &mut self, - origin: LayoutPoint, - spatial_id: di::SpatialId, - prim_flags: di::PrimitiveFlags, - filters: &[di::FilterOp], - filter_datas: &[di::FilterData], - filter_primitives: &[di::FilterPrimitive], - ) { - self.push_stacking_context( - origin, - spatial_id, - prim_flags, - None, - di::TransformStyle::Flat, - di::MixBlendMode::Normal, - filters, - filter_datas, - filter_primitives, - di::RasterSpace::Screen, - di::StackingContextFlags::empty(), - ); - } - - pub fn pop_stacking_context(&mut self) { - self.push_item(&di::DisplayItem::PopStackingContext); - } - - pub fn push_stops(&mut self, stops: &[di::GradientStop]) { - if stops.is_empty() { - return; - } - self.push_item(&di::DisplayItem::SetGradientStops); - self.push_iter(stops); - } - - pub fn push_backdrop_filter( - &mut self, - common: &di::CommonItemProperties, - filters: &[di::FilterOp], - filter_datas: &[di::FilterData], - filter_primitives: &[di::FilterPrimitive], - ) { - self.push_filters(filters, filter_datas, filter_primitives); - - let item = di::DisplayItem::BackdropFilter(di::BackdropFilterDisplayItem { - common: *common, - }); - self.push_item(&item); - } - - pub fn push_filters( - &mut self, - filters: &[di::FilterOp], - filter_datas: &[di::FilterData], - filter_primitives: &[di::FilterPrimitive], - ) { - if !filters.is_empty() { - self.push_item(&di::DisplayItem::SetFilterOps); - self.push_iter(filters); - } - - for filter_data in filter_datas { - let func_types = [ - filter_data.func_r_type, filter_data.func_g_type, - filter_data.func_b_type, filter_data.func_a_type]; - self.push_item(&di::DisplayItem::SetFilterData); - self.push_iter(&func_types); - self.push_iter(&filter_data.r_values); - self.push_iter(&filter_data.g_values); - self.push_iter(&filter_data.b_values); - self.push_iter(&filter_data.a_values); - } - - if !filter_primitives.is_empty() { - self.push_item(&di::DisplayItem::SetFilterPrimitives); - self.push_iter(filter_primitives); - } - } - - fn generate_clip_index(&mut self) -> di::ClipId { - self.next_clip_index += 1; - di::ClipId::Clip(self.next_clip_index - 1, self.pipeline_id) - } - - fn generate_spatial_index(&mut self) -> di::SpatialId { - self.next_spatial_index += 1; - di::SpatialId::new(self.next_spatial_index - 1, self.pipeline_id) - } - - fn generate_clip_chain_id(&mut self) -> di::ClipChainId { - self.next_clip_chain_id += 1; - di::ClipChainId(self.next_clip_chain_id - 1, self.pipeline_id) - } - - pub fn define_scroll_frame( - &mut self, - parent_space_and_clip: &di::SpaceAndClipInfo, - external_id: di::ExternalScrollId, - content_rect: LayoutRect, - clip_rect: LayoutRect, - scroll_sensitivity: di::ScrollSensitivity, - external_scroll_offset: LayoutVector2D, - ) -> di::SpaceAndClipInfo { - let clip_id = self.generate_clip_index(); - let scroll_frame_id = self.generate_spatial_index(); - let item = di::DisplayItem::ScrollFrame(di::ScrollFrameDisplayItem { - content_rect, - clip_rect, - parent_space_and_clip: *parent_space_and_clip, - clip_id, - scroll_frame_id, - external_id, - scroll_sensitivity, - external_scroll_offset, - }); - - self.push_item(&item); - - di::SpaceAndClipInfo { - spatial_id: scroll_frame_id, - clip_id, - } - } - - pub fn define_clip_chain<I>( - &mut self, - parent: Option<di::ClipChainId>, - clips: I, - ) -> di::ClipChainId - where - I: IntoIterator<Item = di::ClipId>, - I::IntoIter: ExactSizeIterator + Clone, - { - let id = self.generate_clip_chain_id(); - self.push_item(&di::DisplayItem::ClipChain(di::ClipChainItem { id, parent })); - self.push_iter(clips); - id - } - - pub fn define_clip_image_mask( - &mut self, - parent_space_and_clip: &di::SpaceAndClipInfo, - image_mask: di::ImageMask, - points: &[LayoutPoint], - fill_rule: di::FillRule, - ) -> di::ClipId { - let id = self.generate_clip_index(); - let item = di::DisplayItem::ImageMaskClip(di::ImageMaskClipDisplayItem { - id, - parent_space_and_clip: *parent_space_and_clip, - image_mask, - fill_rule, - }); - - // We only need to supply points if there are at least 3, which is the - // minimum to specify a polygon. BuiltDisplayListIter.next ensures that points - // are cleared between processing other display items, so we'll correctly get - // zero points when no SetPoints item has been pushed. - if points.len() >= 3 { - self.push_item(&di::DisplayItem::SetPoints); - self.push_iter(points); - } - self.push_item(&item); - id - } - - pub fn define_clip_rect( - &mut self, - parent_space_and_clip: &di::SpaceAndClipInfo, - clip_rect: LayoutRect, - ) -> di::ClipId { - let id = self.generate_clip_index(); - let item = di::DisplayItem::RectClip(di::RectClipDisplayItem { - id, - parent_space_and_clip: *parent_space_and_clip, - clip_rect, - }); - - self.push_item(&item); - id - } - - pub fn define_clip_rounded_rect( - &mut self, - parent_space_and_clip: &di::SpaceAndClipInfo, - clip: di::ComplexClipRegion, - ) -> di::ClipId { - let id = self.generate_clip_index(); - let item = di::DisplayItem::RoundedRectClip(di::RoundedRectClipDisplayItem { - id, - parent_space_and_clip: *parent_space_and_clip, - clip, - }); - - self.push_item(&item); - id - } - - pub fn define_clip<I>( - &mut self, - parent_space_and_clip: &di::SpaceAndClipInfo, - clip_rect: LayoutRect, - complex_clips: I, - ) -> di::ClipId - where - I: IntoIterator<Item = di::ComplexClipRegion>, - I::IntoIter: ExactSizeIterator + Clone, - { - let id = self.generate_clip_index(); - let item = di::DisplayItem::Clip(di::ClipDisplayItem { - id, - parent_space_and_clip: *parent_space_and_clip, - clip_rect, - }); - - self.push_item(&item); - self.push_iter(complex_clips); - id - } - - pub fn define_sticky_frame( - &mut self, - parent_spatial_id: di::SpatialId, - frame_rect: LayoutRect, - margins: SideOffsets2D<Option<f32>, LayoutPixel>, - vertical_offset_bounds: di::StickyOffsetBounds, - horizontal_offset_bounds: di::StickyOffsetBounds, - previously_applied_offset: LayoutVector2D, - ) -> di::SpatialId { - let id = self.generate_spatial_index(); - let item = di::DisplayItem::StickyFrame(di::StickyFrameDisplayItem { - parent_spatial_id, - id, - bounds: frame_rect, - margins, - vertical_offset_bounds, - horizontal_offset_bounds, - previously_applied_offset, - }); - - self.push_item(&item); - id - } - - pub fn push_iframe( - &mut self, - bounds: LayoutRect, - clip_rect: LayoutRect, - space_and_clip: &di::SpaceAndClipInfo, - pipeline_id: PipelineId, - ignore_missing_pipeline: bool - ) { - let item = di::DisplayItem::Iframe(di::IframeDisplayItem { - bounds, - clip_rect, - space_and_clip: *space_and_clip, - pipeline_id, - ignore_missing_pipeline, - }); - self.push_item(&item); - } - - pub fn push_shadow( - &mut self, - space_and_clip: &di::SpaceAndClipInfo, - shadow: di::Shadow, - should_inflate: bool, - ) { - let item = di::DisplayItem::PushShadow(di::PushShadowDisplayItem { - space_and_clip: *space_and_clip, - shadow, - should_inflate, - }); - self.push_item(&item); - } - - pub fn pop_all_shadows(&mut self) { - self.push_item(&di::DisplayItem::PopAllShadows); - } - - pub fn start_item_group(&mut self) { - debug_assert!(!self.writing_to_chunk); - debug_assert!(self.pending_chunk.is_empty()); - - self.writing_to_chunk = true; - } - - fn flush_pending_item_group(&mut self, key: di::ItemKey) { - // Push RetainedItems-marker to extra_data section. - self.push_retained_items(key); - - // Push pending chunk to extra_data section. - self.extra_data.append(&mut self.pending_chunk); - - // Push ReuseItems-marker to data section. - self.push_reuse_items(key); - } - - pub fn finish_item_group(&mut self, key: di::ItemKey) -> bool { - debug_assert!(self.writing_to_chunk); - self.writing_to_chunk = false; - - if self.pending_chunk.is_empty() { - return false; - } - - self.flush_pending_item_group(key); - true - } - - pub fn cancel_item_group(&mut self, discard: bool) { - debug_assert!(self.writing_to_chunk); - self.writing_to_chunk = false; - - if discard { - self.pending_chunk.clear(); - } else { - // Push pending chunk to data section. - self.data.append(&mut self.pending_chunk); - } - } - - pub fn push_reuse_items(&mut self, key: di::ItemKey) { - self.push_item_to_section( - &di::DisplayItem::ReuseItems(key), - DisplayListSection::Data - ); - } - - fn push_retained_items(&mut self, key: di::ItemKey) { - self.push_item_to_section( - &di::DisplayItem::RetainedItems(key), - DisplayListSection::ExtraData - ); - } - - pub fn set_cache_size(&mut self, cache_size: usize) { - self.cache_size = cache_size; - } - - pub fn finalize(mut self) -> (PipelineId, BuiltDisplayList) { - assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save"); - - if let Some(content) = self.serialized_content_buffer.take() { - println!("-- WebRender display list for {:?} --\n{}", - self.pipeline_id, content); - } - - // Add `DisplayItem::max_size` zone of zeroes to the end of display list - // so there is at least this amount available in the display list during - // serialization. - ensure_red_zone::<di::DisplayItem>(&mut self.data); - - let extra_data_offset = self.data.len(); - - if self.extra_data.len() > 0 { - ensure_red_zone::<di::DisplayItem>(&mut self.extra_data); - self.data.extend(self.extra_data); - } - - let end_time = precise_time_ns(); - ( - self.pipeline_id, - BuiltDisplayList { - descriptor: BuiltDisplayListDescriptor { - gecko_display_list_type: GeckoDisplayListType::None, - builder_start_time: self.builder_start_time, - builder_finish_time: end_time, - send_start_time: end_time, - total_clip_nodes: self.next_clip_index, - total_spatial_nodes: self.next_spatial_index, - cache_size: self.cache_size, - extra_data_offset, - }, - data: self.data, - }, - ) - } -} diff --git a/third_party/webrender/webrender_api/src/font.rs b/third_party/webrender/webrender_api/src/font.rs deleted file mode 100644 index 3052db8f9e1..00000000000 --- a/third_party/webrender/webrender_api/src/font.rs +++ /dev/null @@ -1,605 +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 http://mozilla.org/MPL/2.0/. */ - -#[cfg(target_os = "macos")] -use core_foundation::string::CFString; -#[cfg(target_os = "macos")] -use core_graphics::font::CGFont; -use peek_poke::PeekPoke; -#[cfg(target_os = "macos")] -use serde::de::{self, Deserialize, Deserializer}; -#[cfg(target_os = "macos")] -use serde::ser::{Serialize, Serializer}; -use std::cmp::Ordering; -use std::hash::{Hash, Hasher}; -#[cfg(not(target_os = "macos"))] -use std::path::PathBuf; -use std::sync::{Arc, RwLock, RwLockReadGuard}; -use std::collections::HashMap; -// local imports -use crate::IdNamespace; -use crate::channel::Sender; -use crate::color::ColorU; -use crate::units::LayoutPoint; - -/// Hashable floating-point storage for font size. -#[repr(C)] -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, Deserialize, Serialize)] -pub struct FontSize(pub f32); - -impl Ord for FontSize { - fn cmp(&self, other: &FontSize) -> Ordering { - self.partial_cmp(other).unwrap_or(Ordering::Equal) - } -} - -impl Eq for FontSize {} - -impl Hash for FontSize { - fn hash<H: Hasher>(&self, state: &mut H) { - self.0.to_bits().hash(state); - } -} - -impl From<f32> for FontSize { - fn from(size: f32) -> Self { FontSize(size) } -} - -impl From<FontSize> for f32 { - fn from(size: FontSize) -> Self { size.0 } -} - -impl FontSize { - pub fn zero() -> Self { FontSize(0.0) } - - pub fn from_f32_px(size: f32) -> Self { FontSize(size) } - - pub fn to_f32_px(&self) -> f32 { self.0 } - - pub fn from_f64_px(size: f64) -> Self { FontSize(size as f32) } - - pub fn to_f64_px(&self) -> f64 { self.0 as f64 } -} - -/// Immutable description of a font instance requested by the user of the API. -/// -/// `BaseFontInstance` can be identified by a `FontInstanceKey` so we should -/// never need to hash it. -#[derive(Clone, PartialEq, Eq, Debug, Ord, PartialOrd, MallocSizeOf)] -#[cfg_attr(feature = "serialize", derive(Serialize))] -#[cfg_attr(feature = "deserialize", derive(Deserialize))] -pub struct BaseFontInstance { - /// - pub instance_key: FontInstanceKey, - /// - pub font_key: FontKey, - /// - pub size: FontSize, - /// - pub bg_color: ColorU, - /// - pub render_mode: FontRenderMode, - /// - pub flags: FontInstanceFlags, - /// - pub synthetic_italics: SyntheticItalics, - /// - #[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))] - pub platform_options: Option<FontInstancePlatformOptions>, - /// - pub variations: Vec<FontVariation>, -} - -pub type FontInstanceMap = HashMap<FontInstanceKey, Arc<BaseFontInstance>>; -/// A map of font instance data accessed concurrently from multiple threads. -#[derive(Clone)] -#[cfg_attr(feature = "serialize", derive(Serialize))] -#[cfg_attr(feature = "deserialize", derive(Deserialize))] -pub struct SharedFontInstanceMap { - map: Arc<RwLock<FontInstanceMap>>, -} - -impl SharedFontInstanceMap { - /// Creates an empty shared map. - pub fn new() -> Self { - SharedFontInstanceMap { - map: Arc::new(RwLock::new(HashMap::default())) - } - } - - /// Acquires a write lock on the shared map. - pub fn lock(&mut self) -> Option<RwLockReadGuard<FontInstanceMap>> { - self.map.read().ok() - } - - /// - pub fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> { - match self.map.read().unwrap().get(&key) { - Some(instance) => Some(FontInstanceData { - font_key: instance.font_key, - size: instance.size.into(), - options: Some(FontInstanceOptions { - render_mode: instance.render_mode, - flags: instance.flags, - bg_color: instance.bg_color, - synthetic_italics: instance.synthetic_italics, - }), - platform_options: instance.platform_options, - variations: instance.variations.clone(), - }), - None => None, - } - } - - /// Replace the shared map with the provided map. - pub fn set(&mut self, map: FontInstanceMap) { - *self.map.write().unwrap() = map; - } - - /// - pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> { - let instance_map = self.map.read().unwrap(); - instance_map.get(&instance_key).map(|instance| { Arc::clone(instance) }) - } - - /// - pub fn add_font_instance( - &mut self, - instance_key: FontInstanceKey, - font_key: FontKey, - size: f32, - options: Option<FontInstanceOptions>, - platform_options: Option<FontInstancePlatformOptions>, - variations: Vec<FontVariation>, - ) { - let FontInstanceOptions { - render_mode, - flags, - bg_color, - synthetic_italics, - .. - } = options.unwrap_or_default(); - - let instance = Arc::new(BaseFontInstance { - instance_key, - font_key, - size: size.into(), - bg_color, - render_mode, - flags, - synthetic_italics, - platform_options, - variations, - }); - - self.map - .write() - .unwrap() - .insert(instance_key, instance); - } - - /// - pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) { - self.map.write().unwrap().remove(&instance_key); - } - - /// - pub fn clear_namespace(&mut self, namespace: IdNamespace) { - self.map - .write() - .unwrap() - .retain(|key, _| key.0 != namespace); - } - - /// - pub fn clone_map(&self) -> FontInstanceMap { - self.map.read().unwrap().clone() - } -} - -#[cfg(not(target_os = "macos"))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct NativeFontHandle { - pub path: PathBuf, - pub index: u32, -} - -#[cfg(target_os = "macos")] -#[derive(Clone)] -pub struct NativeFontHandle(pub CGFont); - -#[cfg(target_os = "macos")] -impl Serialize for NativeFontHandle { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - self.0 - .postscript_name() - .to_string() - .serialize(serializer) - } -} - -#[cfg(target_os = "macos")] -impl<'de> Deserialize<'de> for NativeFontHandle { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - let postscript_name: String = Deserialize::deserialize(deserializer)?; - - match CGFont::from_name(&CFString::new(&*postscript_name)) { - Ok(font) => Ok(NativeFontHandle(font)), - Err(_) => Err(de::Error::custom( - "Couldn't find a font with that PostScript name!", - )), - } - } -} - -#[repr(C)] -#[derive(Copy, Clone, Deserialize, Serialize, Debug)] -pub struct GlyphDimensions { - pub left: i32, - pub top: i32, - pub width: i32, - pub height: i32, - pub advance: f32, -} - -pub struct GlyphDimensionRequest { - pub key: FontInstanceKey, - pub glyph_indices: Vec<GlyphIndex>, - pub sender: Sender<Vec<Option<GlyphDimensions>>>, -} - -pub struct GlyphIndexRequest { - pub key: FontKey, - pub text: String, - pub sender: Sender<Vec<Option<u32>>>, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, Ord, PartialOrd)] -pub struct FontKey(pub IdNamespace, pub u32); - -impl FontKey { - pub fn new(namespace: IdNamespace, key: u32) -> FontKey { - FontKey(namespace, key) - } -} - -/// Container for the raw data describing a font. This might be a stream of -/// bytes corresponding to a downloaded font, or a handle to a native font from -/// the operating system. -/// -/// Note that fonts need to be instantiated before being used, which involves -/// assigning size and various other options. The word 'template' here is -/// intended to distinguish this data from instance-specific data. -#[derive(Clone)] -pub enum FontTemplate { - Raw(Arc<Vec<u8>>, u32), - Native(NativeFontHandle), -} - -#[repr(u8)] -#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)] -pub enum FontRenderMode { - Mono = 0, - Alpha, - Subpixel, -} - -impl Default for FontRenderMode { - fn default() -> Self { - FontRenderMode::Mono - } -} - -impl FontRenderMode { - // Combine two font render modes such that the lesser amount of AA limits the AA of the result. - pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode { - match (self, other) { - (FontRenderMode::Subpixel, _) | (_, FontRenderMode::Mono) => other, - _ => self, - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialOrd, Deserialize, Serialize)] -pub struct FontVariation { - pub tag: u32, - pub value: f32, -} - -impl Ord for FontVariation { - fn cmp(&self, other: &FontVariation) -> Ordering { - self.tag.cmp(&other.tag) - .then(self.value.to_bits().cmp(&other.value.to_bits())) - } -} - -impl PartialEq for FontVariation { - fn eq(&self, other: &FontVariation) -> bool { - self.tag == other.tag && - self.value.to_bits() == other.value.to_bits() - } -} - -impl Eq for FontVariation {} - -impl Hash for FontVariation { - fn hash<H: Hasher>(&self, state: &mut H) { - self.tag.hash(state); - self.value.to_bits().hash(state); - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, PeekPoke)] -pub struct GlyphOptions { - pub render_mode: FontRenderMode, - pub flags: FontInstanceFlags, -} - -impl Default for GlyphOptions { - fn default() -> Self { - GlyphOptions { - render_mode: FontRenderMode::Subpixel, - flags: FontInstanceFlags::empty(), - } - } -} - -bitflags! { - #[repr(C)] - #[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)] - pub struct FontInstanceFlags: u32 { - // Common flags - const SYNTHETIC_BOLD = 1 << 1; - const EMBEDDED_BITMAPS = 1 << 2; - const SUBPIXEL_BGR = 1 << 3; - const TRANSPOSE = 1 << 4; - const FLIP_X = 1 << 5; - const FLIP_Y = 1 << 6; - const SUBPIXEL_POSITION = 1 << 7; - const VERTICAL = 1 << 8; - - // Internal flags - const TRANSFORM_GLYPHS = 1 << 12; - const TEXTURE_PADDING = 1 << 13; - - // Windows flags - const FORCE_GDI = 1 << 16; - const FORCE_SYMMETRIC = 1 << 17; - const NO_SYMMETRIC = 1 << 18; - - // Mac flags - const FONT_SMOOTHING = 1 << 16; - - // FreeType flags - const FORCE_AUTOHINT = 1 << 16; - const NO_AUTOHINT = 1 << 17; - const VERTICAL_LAYOUT = 1 << 18; - const LCD_VERTICAL = 1 << 19; - } -} - -impl Default for FontInstanceFlags { - #[cfg(target_os = "windows")] - fn default() -> FontInstanceFlags { - FontInstanceFlags::SUBPIXEL_POSITION - } - - #[cfg(target_os = "macos")] - fn default() -> FontInstanceFlags { - FontInstanceFlags::SUBPIXEL_POSITION | - FontInstanceFlags::FONT_SMOOTHING - } - - #[cfg(not(any(target_os = "macos", target_os = "windows")))] - fn default() -> FontInstanceFlags { - FontInstanceFlags::SUBPIXEL_POSITION - } -} - - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub struct SyntheticItalics { - // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point. - pub angle: i16, -} - -impl SyntheticItalics { - pub const ANGLE_SCALE: f32 = 256.0; - - pub fn from_degrees(degrees: f32) -> Self { - SyntheticItalics { angle: (degrees.max(-89.0).min(89.0) * Self::ANGLE_SCALE) as i16 } - } - - pub fn to_degrees(self) -> f32 { - self.angle as f32 / Self::ANGLE_SCALE - } - - pub fn to_radians(self) -> f32 { - self.to_degrees().to_radians() - } - - pub fn to_skew(self) -> f32 { - self.to_radians().tan() - } - - pub fn enabled() -> Self { - Self::from_degrees(14.0) - } - - pub fn disabled() -> Self { - SyntheticItalics { angle: 0 } - } - - pub fn is_enabled(self) -> bool { - self.angle != 0 - } -} - -impl Default for SyntheticItalics { - fn default() -> Self { - SyntheticItalics::disabled() - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)] -pub struct FontInstanceOptions { - pub render_mode: FontRenderMode, - pub flags: FontInstanceFlags, - /// When bg_color.a is != 0 and render_mode is FontRenderMode::Subpixel, - /// the text will be rendered with bg_color.r/g/b as an opaque estimated - /// background color. - pub bg_color: ColorU, - pub synthetic_italics: SyntheticItalics, -} - -impl Default for FontInstanceOptions { - fn default() -> FontInstanceOptions { - FontInstanceOptions { - render_mode: FontRenderMode::Subpixel, - flags: Default::default(), - bg_color: ColorU::new(0, 0, 0, 0), - synthetic_italics: SyntheticItalics::disabled(), - } - } -} - -#[cfg(target_os = "windows")] -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub struct FontInstancePlatformOptions { - pub gamma: u16, // percent - pub contrast: u8, // percent - pub cleartype_level: u8, // percent -} - -#[cfg(target_os = "windows")] -impl Default for FontInstancePlatformOptions { - fn default() -> FontInstancePlatformOptions { - FontInstancePlatformOptions { - gamma: 180, // Default DWrite gamma - contrast: 100, - cleartype_level: 100, - } - } -} - -#[cfg(target_os = "macos")] -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub struct FontInstancePlatformOptions { - pub unused: u32, -} - -#[cfg(target_os = "macos")] -impl Default for FontInstancePlatformOptions { - fn default() -> FontInstancePlatformOptions { - FontInstancePlatformOptions { - unused: 0, - } - } -} - -#[cfg(not(any(target_os = "macos", target_os = "windows")))] -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub enum FontLCDFilter { - None, - Default, - Light, - Legacy, -} - -#[cfg(not(any(target_os = "macos", target_os = "windows")))] -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub enum FontHinting { - None, - Mono, - Light, - Normal, - LCD, -} - -#[cfg(not(any(target_os = "macos", target_os = "windows")))] -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] -pub struct FontInstancePlatformOptions { - pub lcd_filter: FontLCDFilter, - pub hinting: FontHinting, -} - -#[cfg(not(any(target_os = "macos", target_os = "windows")))] -impl Default for FontInstancePlatformOptions { - fn default() -> FontInstancePlatformOptions { - FontInstancePlatformOptions { - lcd_filter: FontLCDFilter::Default, - hinting: FontHinting::LCD, - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd, MallocSizeOf, PeekPoke)] -#[derive(Deserialize, Serialize)] -pub struct FontInstanceKey(pub IdNamespace, pub u32); - -impl FontInstanceKey { - pub fn new(namespace: IdNamespace, key: u32) -> FontInstanceKey { - FontInstanceKey(namespace, key) - } -} - -/// Data corresponding to an instantiation of a font, with size and -/// other options specified. -/// -/// Note that the actual font is stored out-of-band in `FontTemplate`. -#[derive(Clone)] -pub struct FontInstanceData { - pub font_key: FontKey, - pub size: f32, - pub options: Option<FontInstanceOptions>, - pub platform_options: Option<FontInstancePlatformOptions>, - pub variations: Vec<FontVariation>, -} - -pub type GlyphIndex = u32; - -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct GlyphInstance { - pub index: GlyphIndex, - pub point: LayoutPoint, -} - -impl Default for GlyphInstance { - fn default() -> Self { - GlyphInstance { - index: 0, - point: LayoutPoint::zero(), - } - } -} - -impl Eq for GlyphInstance {} - -#[cfg_attr(feature = "cargo-clippy", allow(clippy::derive_hash_xor_eq))] -impl Hash for GlyphInstance { - fn hash<H: Hasher>(&self, state: &mut H) { - // Note: this is inconsistent with the Eq impl for -0.0 (don't care). - self.index.hash(state); - self.point.x.to_bits().hash(state); - self.point.y.to_bits().hash(state); - } -} diff --git a/third_party/webrender/webrender_api/src/gradient_builder.rs b/third_party/webrender/webrender_api/src/gradient_builder.rs deleted file mode 100644 index 6347396f791..00000000000 --- a/third_party/webrender/webrender_api/src/gradient_builder.rs +++ /dev/null @@ -1,180 +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 http://mozilla.org/MPL/2.0/. */ - -use crate::display_item as di; -use crate::units::*; - - -/// Construct a gradient to be used in display lists. -/// -/// Each gradient needs at least two stops. -pub struct GradientBuilder { - stops: Vec<di::GradientStop>, -} - -impl GradientBuilder { - /// Create a new gradient builder. - pub fn new() -> Self { - GradientBuilder { - stops: Vec::new(), - } - } - - /// Create a gradient builder with a list of stops. - pub fn with_stops(stops: Vec<di::GradientStop>) -> GradientBuilder { - GradientBuilder { stops } - } - - /// Push an additional stop for the gradient. - pub fn push(&mut self, stop: di::GradientStop) { - self.stops.push(stop); - } - - /// Get a reference to the list of stops. - pub fn stops(&self) -> &[di::GradientStop] { - self.stops.as_ref() - } - - /// Return the gradient stops vector. - pub fn into_stops(self) -> Vec<di::GradientStop> { - self.stops - } - - /// Produce a linear gradient, normalize the stops. - pub fn gradient( - &mut self, - start_point: LayoutPoint, - end_point: LayoutPoint, - extend_mode: di::ExtendMode, - ) -> di::Gradient { - let (start_offset, end_offset) = self.normalize(extend_mode); - let start_to_end = end_point - start_point; - - di::Gradient { - start_point: start_point + start_to_end * start_offset, - end_point: start_point + start_to_end * end_offset, - extend_mode, - } - } - - /// Produce a radial gradient, normalize the stops. - /// - /// Will replace the gradient with a single color - /// if the radius negative. - pub fn radial_gradient( - &mut self, - center: LayoutPoint, - radius: LayoutSize, - extend_mode: di::ExtendMode, - ) -> di::RadialGradient { - if radius.width <= 0.0 || radius.height <= 0.0 { - // The shader cannot handle a non positive radius. So - // reuse the stops vector and construct an equivalent - // gradient. - let last_color = self.stops.last().unwrap().color; - - self.stops.clear(); - self.stops.push(di::GradientStop { offset: 0.0, color: last_color, }); - self.stops.push(di::GradientStop { offset: 1.0, color: last_color, }); - - return di::RadialGradient { - center, - radius: LayoutSize::new(1.0, 1.0), - start_offset: 0.0, - end_offset: 1.0, - extend_mode, - }; - } - - let (start_offset, end_offset) = - self.normalize(extend_mode); - - di::RadialGradient { - center, - radius, - start_offset, - end_offset, - extend_mode, - } - } - - /// Produce a conic gradient, normalize the stops. - pub fn conic_gradient( - &mut self, - center: LayoutPoint, - angle: f32, - extend_mode: di::ExtendMode, - ) -> di::ConicGradient { - let (start_offset, end_offset) = - self.normalize(extend_mode); - - di::ConicGradient { - center, - angle, - start_offset, - end_offset, - extend_mode, - } - } - - /// Gradients can be defined with stops outside the range of [0, 1] - /// when this happens the gradient needs to be normalized by adjusting - /// the gradient stops and gradient line into an equivalent gradient - /// with stops in the range [0, 1]. this is done by moving the beginning - /// of the gradient line to where stop[0] and the end of the gradient line - /// to stop[n-1]. this function adjusts the stops in place, and returns - /// the amount to adjust the gradient line start and stop. - fn normalize(&mut self, extend_mode: di::ExtendMode) -> (f32, f32) { - let stops = &mut self.stops; - assert!(stops.len() >= 2); - - let first = *stops.first().unwrap(); - let last = *stops.last().unwrap(); - - // Express the assertion so that if one of the offsets is NaN, we don't panic - // and instead take the branch that handles degenerate gradients. - assert!(!(first.offset > last.offset)); - - let stops_delta = last.offset - first.offset; - - if stops_delta > 0.000001 { - for stop in stops { - stop.offset = (stop.offset - first.offset) / stops_delta; - } - - (first.offset, last.offset) - } else { - // We have a degenerate gradient and can't accurately transform the stops - // what happens here depends on the repeat behavior, but in any case - // we reconstruct the gradient stops to something simpler and equivalent - stops.clear(); - - match extend_mode { - di::ExtendMode::Clamp => { - // This gradient is two colors split at the offset of the stops, - // so create a gradient with two colors split at 0.5 and adjust - // the gradient line so 0.5 is at the offset of the stops - stops.push(di::GradientStop { color: first.color, offset: 0.0, }); - stops.push(di::GradientStop { color: first.color, offset: 0.5, }); - stops.push(di::GradientStop { color: last.color, offset: 0.5, }); - stops.push(di::GradientStop { color: last.color, offset: 1.0, }); - - let offset = last.offset; - - (offset - 0.5, offset + 0.5) - } - di::ExtendMode::Repeat => { - // A repeating gradient with stops that are all in the same - // position should just display the last color. I believe the - // spec says that it should be the average color of the gradient, - // but this matches what Gecko and Blink does - stops.push(di::GradientStop { color: last.color, offset: 0.0, }); - stops.push(di::GradientStop { color: last.color, offset: 1.0, }); - - (0.0, 1.0) - } - } - } - } -} diff --git a/third_party/webrender/webrender_api/src/image.rs b/third_party/webrender/webrender_api/src/image.rs deleted file mode 100644 index 23c660b647e..00000000000 --- a/third_party/webrender/webrender_api/src/image.rs +++ /dev/null @@ -1,580 +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 http://mozilla.org/MPL/2.0/. */ - -#![deny(missing_docs)] - -use euclid::{size2, Rect, num::Zero}; -use peek_poke::PeekPoke; -use std::ops::{Add, Sub}; -use std::sync::Arc; -// local imports -use crate::{IdNamespace, TileSize}; -use crate::display_item::ImageRendering; -use crate::font::{FontInstanceKey, FontInstanceData, FontKey, FontTemplate}; -use crate::units::*; - -/// The default tile size for blob images and regular images larger than -/// the maximum texture size. -pub const DEFAULT_TILE_SIZE: TileSize = 512; - -/// An opaque identifier describing an image registered with WebRender. -/// This is used as a handle to reference images, and is used as the -/// hash map key for the actual image storage in the `ResourceCache`. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct ImageKey(pub IdNamespace, pub u32); - -impl Default for ImageKey { - fn default() -> Self { - ImageKey::DUMMY - } -} - -impl ImageKey { - /// Placeholder Image key, used to represent None. - pub const DUMMY: Self = ImageKey(IdNamespace(0), 0); - - /// Mints a new ImageKey. The given ID must be unique. - pub fn new(namespace: IdNamespace, key: u32) -> Self { - ImageKey(namespace, key) - } -} - -/// An opaque identifier describing a blob image registered with WebRender. -/// This is used as a handle to reference blob images, and can be used as an -/// image in display items. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct BlobImageKey(pub ImageKey); - -impl BlobImageKey { - /// Interpret this blob image as an image for a display item. - pub fn as_image(self) -> ImageKey { - self.0 - } -} - -/// An arbitrary identifier for an external image provided by the -/// application. It must be a unique identifier for each external -/// image. -#[repr(C)] -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] -pub struct ExternalImageId(pub u64); - -/// The source for an external image. -pub enum ExternalImageSource<'a> { - /// A raw pixel buffer. - RawData(&'a [u8]), - /// A gl::GLuint texture handle. - NativeTexture(u32), - /// An invalid source. - Invalid, -} - -/// The data that an external client should provide about -/// an external image. For instance, if providing video frames, -/// the application could call wr.render() whenever a new -/// video frame is ready. Note that the UV coords are supplied -/// in texel-space! -pub struct ExternalImage<'a> { - /// UV coordinates for the image. - pub uv: TexelRect, - /// The source for this image's contents. - pub source: ExternalImageSource<'a>, -} - -/// The interfaces that an application can implement to support providing -/// external image buffers. -/// When the application passes an external image to WR, it should keep that -/// external image life time. People could check the epoch id in RenderNotifier -/// at the client side to make sure that the external image is not used by WR. -/// Then, do the clean up for that external image. -pub trait ExternalImageHandler { - /// Lock the external image. Then, WR could start to read the image content. - /// The WR client should not change the image content until the unlock() - /// call. Provide ImageRendering for NativeTexture external images. - fn lock(&mut self, key: ExternalImageId, channel_index: u8, rendering: ImageRendering) -> ExternalImage; - /// Unlock the external image. WR should not read the image content - /// after this call. - fn unlock(&mut self, key: ExternalImageId, channel_index: u8); -} - -/// Specifies the type of texture target in driver terms. -#[repr(u8)] -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub enum ImageBufferKind { - /// Standard texture. This maps to GL_TEXTURE_2D in OpenGL. - Texture2D = 0, - /// Rectangle texture. This maps to GL_TEXTURE_RECTANGLE in OpenGL. This - /// is similar to a standard texture, with a few subtle differences - /// (no mipmaps, non-power-of-two dimensions, different coordinate space) - /// that make it useful for representing the kinds of textures we use - /// in WebRender. See https://www.khronos.org/opengl/wiki/Rectangle_Texture - /// for background on Rectangle textures. - TextureRect = 1, - /// External texture. This maps to GL_TEXTURE_EXTERNAL_OES in OpenGL, which - /// is an extension. This is used for image formats that OpenGL doesn't - /// understand, particularly YUV. See - /// https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt - TextureExternal = 2, -} - -/// Storage format identifier for externally-managed images. -#[repr(u8)] -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum ExternalImageType { - /// The image is texture-backed. - TextureHandle(ImageBufferKind), - /// The image is heap-allocated by the embedding. - Buffer, -} - -/// Descriptor for external image resources. See `ImageData`. -#[repr(C)] -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct ExternalImageData { - /// The identifier of this external image, provided by the embedding. - pub id: ExternalImageId, - /// For multi-plane images (i.e. YUV), indicates the plane of the - /// original image that this struct represents. 0 for single-plane images. - pub channel_index: u8, - /// Storage format identifier. - pub image_type: ExternalImageType, -} - -/// Specifies the format of a series of pixels, in driver terms. -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub enum ImageFormat { - /// One-channel, byte storage. The "red" doesn't map to the color - /// red per se, and is just the way that OpenGL has historically referred - /// to single-channel buffers. - R8 = 1, - /// One-channel, short storage - R16 = 2, - /// Four channels, byte storage. - BGRA8 = 3, - /// Four channels, float storage. - RGBAF32 = 4, - /// Two-channels, byte storage. Similar to `R8`, this just means - /// "two channels" rather than "red and green". - RG8 = 5, - /// Two-channels, byte storage. Similar to `R16`, this just means - /// "two channels" rather than "red and green". - RG16 = 6, - - /// Four channels, signed integer storage. - RGBAI32 = 7, - /// Four channels, byte storage. - RGBA8 = 8, -} - -impl ImageFormat { - /// Returns the number of bytes per pixel for the given format. - pub fn bytes_per_pixel(self) -> i32 { - match self { - ImageFormat::R8 => 1, - ImageFormat::R16 => 2, - ImageFormat::BGRA8 => 4, - ImageFormat::RGBAF32 => 16, - ImageFormat::RG8 => 2, - ImageFormat::RG16 => 4, - ImageFormat::RGBAI32 => 16, - ImageFormat::RGBA8 => 4, - } - } -} - -/// Specifies the color depth of an image. Currently only used for YUV images. -#[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum ColorDepth { - /// 8 bits image (most common) - Color8, - /// 10 bits image - Color10, - /// 12 bits image - Color12, - /// 16 bits image - Color16, -} - -impl Default for ColorDepth { - fn default() -> Self { - ColorDepth::Color8 - } -} - -impl ColorDepth { - /// Return the numerical bit depth value for the type. - pub fn bit_depth(self) -> u32 { - match self { - ColorDepth::Color8 => 8, - ColorDepth::Color10 => 10, - ColorDepth::Color12 => 12, - ColorDepth::Color16 => 16, - } - } - /// 10 and 12 bits images are encoded using 16 bits integer, we need to - /// rescale the 10 or 12 bits value to extend to 16 bits. - pub fn rescaling_factor(self) -> f32 { - match self { - ColorDepth::Color8 => 1.0, - ColorDepth::Color10 => 64.0, - ColorDepth::Color12 => 16.0, - ColorDepth::Color16 => 1.0, - } - } -} - -bitflags! { - /// Various flags that are part of an image descriptor. - #[derive(Deserialize, Serialize)] - pub struct ImageDescriptorFlags: u32 { - /// Whether this image is opaque, or has an alpha channel. Avoiding blending - /// for opaque surfaces is an important optimization. - const IS_OPAQUE = 1; - /// Whether to allow the driver to automatically generate mipmaps. If images - /// are already downscaled appropriately, mipmap generation can be wasted - /// work, and cause performance problems on some cards/drivers. - /// - /// See https://github.com/servo/webrender/pull/2555/ - const ALLOW_MIPMAPS = 2; - } -} - -/// Metadata (but not storage) describing an image In WebRender. -#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct ImageDescriptor { - /// Format of the image data. - pub format: ImageFormat, - /// Width and length of the image data, in pixels. - pub size: DeviceIntSize, - /// The number of bytes from the start of one row to the next. If non-None, - /// `compute_stride` will return this value, otherwise it returns - /// `width * bpp`. Different source of images have different alignment - /// constraints for rows, so the stride isn't always equal to width * bpp. - pub stride: Option<i32>, - /// Offset in bytes of the first pixel of this image in its backing buffer. - /// This is used for tiling, wherein WebRender extracts chunks of input images - /// in order to cache, manipulate, and render them individually. This offset - /// tells the texture upload machinery where to find the bytes to upload for - /// this tile. Non-tiled images generally set this to zero. - pub offset: i32, - /// Various bool flags related to this descriptor. - pub flags: ImageDescriptorFlags, -} - -impl ImageDescriptor { - /// Mints a new ImageDescriptor. - pub fn new( - width: i32, - height: i32, - format: ImageFormat, - flags: ImageDescriptorFlags, - ) -> Self { - ImageDescriptor { - size: size2(width, height), - format, - stride: None, - offset: 0, - flags, - } - } - - /// Returns the stride, either via an explicit stride stashed on the object - /// or by the default computation. - pub fn compute_stride(&self) -> i32 { - self.stride.unwrap_or(self.size.width * self.format.bytes_per_pixel()) - } - - /// Computes the total size of the image, in bytes. - pub fn compute_total_size(&self) -> i32 { - self.compute_stride() * self.size.height - } - - /// Computes the bounding rectangle for the image, rooted at (0, 0). - pub fn full_rect(&self) -> DeviceIntRect { - DeviceIntRect::new( - DeviceIntPoint::zero(), - self.size, - ) - } - - /// Returns true if this descriptor is opaque - pub fn is_opaque(&self) -> bool { - self.flags.contains(ImageDescriptorFlags::IS_OPAQUE) - } - - /// Returns true if this descriptor allows mipmaps - pub fn allow_mipmaps(&self) -> bool { - self.flags.contains(ImageDescriptorFlags::ALLOW_MIPMAPS) - } -} - -/// Represents the backing store of an arbitrary series of pixels for display by -/// WebRender. This storage can take several forms. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ImageData { - /// A simple series of bytes, provided by the embedding and owned by WebRender. - /// The format is stored out-of-band, currently in ImageDescriptor. - Raw(#[serde(with = "serde_image_data_raw")] Arc<Vec<u8>>), - /// 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), -} - -mod serde_image_data_raw { - use serde::{Deserializer, Serializer}; - use serde_bytes; - use std::sync::Arc; - - pub fn serialize<S: Serializer>(bytes: &Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error> { - serde_bytes::serialize(bytes.as_slice(), serializer) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Arc<Vec<u8>>, D::Error> { - serde_bytes::deserialize(deserializer).map(Arc::new) - } -} - -impl ImageData { - /// Mints a new raw ImageData, taking ownership of the bytes. - pub fn new(bytes: Vec<u8>) -> Self { - ImageData::Raw(Arc::new(bytes)) - } - - /// Mints a new raw ImageData from Arc-ed bytes. - pub fn new_shared(bytes: Arc<Vec<u8>>) -> Self { - ImageData::Raw(bytes) - } -} - -/// The resources exposed by the resource cache available for use by the blob rasterizer. -pub trait BlobImageResources { - /// Returns the `FontTemplate` for the given key. - fn get_font_data(&self, key: FontKey) -> &FontTemplate; - /// Returns the `FontInstanceData` for the given key, if found. - fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData>; -} - -/// A handler on the render backend that can create rasterizer objects which will -/// be sent to the scene builder thread to execute the rasterization. -/// -/// The handler is responsible for collecting resources, managing/updating blob commands -/// and creating the rasterizer objects, but isn't expected to do any rasterization itself. -pub trait BlobImageHandler: Send { - /// Creates a snapshot of the current state of blob images in the handler. - fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer>; - - /// Creates an empty blob handler of the same type. - /// - /// This is used to allow creating new API endpoints with blob handlers installed on them. - fn create_similar(&self) -> Box<dyn BlobImageHandler>; - - /// A hook to let the blob image handler update any state related to resources that - /// are not bundled in the blob recording itself. - fn prepare_resources( - &mut self, - services: &dyn BlobImageResources, - requests: &[BlobImageParams], - ); - - /// Register a blob image. - fn add(&mut self, key: BlobImageKey, data: Arc<BlobImageData>, visible_rect: &DeviceIntRect, - tile_size: TileSize); - - /// Update an already registered blob image. - fn update(&mut self, key: BlobImageKey, data: Arc<BlobImageData>, visible_rect: &DeviceIntRect, - dirty_rect: &BlobDirtyRect); - - /// Delete an already registered blob image. - fn delete(&mut self, key: BlobImageKey); - - /// A hook to let the handler clean up any state related to a font which the resource - /// cache is about to delete. - fn delete_font(&mut self, key: FontKey); - - /// A hook to let the handler clean up any state related to a font instance which the - /// resource cache is about to delete. - fn delete_font_instance(&mut self, key: FontInstanceKey); - - /// A hook to let the handler clean up any state related a given namespace before the - /// resource cache deletes them. - fn clear_namespace(&mut self, namespace: IdNamespace); - - /// Whether to allow rendering blobs on multiple threads. - fn enable_multithreading(&mut self, enable: bool); -} - -/// A group of rasterization requests to execute synchronously on the scene builder thread. -pub trait AsyncBlobImageRasterizer : Send { - /// Rasterize the requests. - /// - /// Gecko uses te priority hint to schedule work in a way that minimizes the risk - /// of high priority work being blocked by (or enqued behind) low priority work. - fn rasterize( - &mut self, - requests: &[BlobImageParams], - low_priority: bool - ) -> Vec<(BlobImageRequest, BlobImageResult)>; -} - - -/// Input parameters for the BlobImageRasterizer. -#[derive(Copy, Clone, Debug)] -pub struct BlobImageParams { - /// A key that identifies the blob image rasterization request. - pub request: BlobImageRequest, - /// Description of the format of the blob's output image. - pub descriptor: BlobImageDescriptor, - /// An optional sub-rectangle of the image to avoid re-rasterizing - /// the entire image when only a portion is updated. - /// - /// If set to None the entire image is rasterized. - pub dirty_rect: BlobDirtyRect, -} - -/// The possible states of a Dirty rect. -/// -/// This exists because people kept getting confused with `Option<Rect>`. -#[derive(Debug, Serialize, Deserialize)] -pub enum DirtyRect<T: Copy, U> { - /// Everything is Dirty, equivalent to Partial(image_bounds) - All, - /// Some specific amount is dirty - Partial(Rect<T, U>) -} - -impl<T, U> DirtyRect<T, U> -where - T: Copy + Clone - + PartialOrd + PartialEq - + Add<T, Output = T> - + Sub<T, Output = T> - + Zero -{ - /// Creates an empty DirtyRect (indicating nothing is invalid) - pub fn empty() -> Self { - DirtyRect::Partial(Rect::zero()) - } - - /// Returns whether the dirty rect is empty - pub fn is_empty(&self) -> bool { - match self { - DirtyRect::All => false, - DirtyRect::Partial(rect) => rect.is_empty(), - } - } - - /// Replaces self with the empty rect and returns the old value. - pub fn replace_with_empty(&mut self) -> Self { - ::std::mem::replace(self, DirtyRect::empty()) - } - - /// Maps over the contents of Partial. - pub fn map<F>(self, func: F) -> Self - where F: FnOnce(Rect<T, U>) -> Rect<T, U>, - { - use crate::DirtyRect::*; - - match self { - All => All, - Partial(rect) => Partial(func(rect)), - } - } - - /// Unions the dirty rects. - pub fn union(&self, other: &Self) -> Self { - use crate::DirtyRect::*; - - match (*self, *other) { - (All, _) | (_, All) => All, - (Partial(rect1), Partial(rect2)) => Partial(rect1.union(&rect2)), - } - } - - /// Intersects the dirty rects. - pub fn intersection(&self, other: &Self) -> Self { - use crate::DirtyRect::*; - - match (*self, *other) { - (All, rect) | (rect, All) => rect, - (Partial(rect1), Partial(rect2)) => { - Partial(rect1.intersection(&rect2).unwrap_or_else(Rect::zero)) - } - } - } - - /// Converts the dirty rect into a subrect of the given one via intersection. - pub fn to_subrect_of(&self, rect: &Rect<T, U>) -> Rect<T, U> { - use crate::DirtyRect::*; - - match *self { - All => *rect, - Partial(dirty_rect) => { - dirty_rect.intersection(rect).unwrap_or_else(Rect::zero) - } - } - } -} - -impl<T: Copy, U> Copy for DirtyRect<T, U> {} -impl<T: Copy, U> Clone for DirtyRect<T, U> { - fn clone(&self) -> Self { *self } -} - -impl<T: Copy, U> From<Rect<T, U>> for DirtyRect<T, U> { - fn from(rect: Rect<T, U>) -> Self { - DirtyRect::Partial(rect) - } -} - -/// Backing store for blob image command streams. -pub type BlobImageData = Vec<u8>; - -/// Result type for blob raserization. -pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>; - -/// Metadata (but not storage) for a blob image. -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct BlobImageDescriptor { - /// Surface of the image or tile to render in the same coordinate space as - /// the drawing commands. - pub rect: LayoutIntRect, - /// Format for the data in the backing store. - pub format: ImageFormat, -} - -/// Representation of a rasterized blob image. This is obtained by passing -/// `BlobImageData` to the embedding via the rasterization callback. -pub struct RasterizedBlobImage { - /// The rectangle that was rasterized in device pixels, relative to the - /// image or tile. - pub rasterized_rect: DeviceIntRect, - /// Backing store. The format is stored out of band in `BlobImageDescriptor`. - pub data: Arc<Vec<u8>>, -} - -/// Error code for when blob rasterization failed. -#[derive(Clone, Debug)] -pub enum BlobImageError { - /// Out of memory. - Oom, - /// Other failure, embedding-specified. - Other(String), -} - - - -/// A key identifying blob image rasterization work requested from the blob -/// image rasterizer. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct BlobImageRequest { - /// Unique handle to the image. - pub key: BlobImageKey, - /// Tiling offset in number of tiles. - pub tile: TileOffset, -} diff --git a/third_party/webrender/webrender_api/src/lib.rs b/third_party/webrender/webrender_api/src/lib.rs deleted file mode 100644 index f5cda1fbf65..00000000000 --- a/third_party/webrender/webrender_api/src/lib.rs +++ /dev/null @@ -1,665 +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 http://mozilla.org/MPL/2.0/. */ - -//! The `webrender_api` crate contains an assortment types and functions used -//! by WebRender consumers as well as, in many cases, WebRender itself. -//! -//! This separation allows Servo to parallelize compilation across `webrender` -//! and other crates that depend on `webrender_api`. So in practice, we put -//! things in this crate when Servo needs to use them. Firefox depends on the -//! `webrender` crate directly, and so this distinction is not really relevant -//! there. - -#![cfg_attr(feature = "nightly", feature(nonzero))] -#![cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp, clippy::too_many_arguments))] -#![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal, clippy::new_without_default))] - -pub use crossbeam_channel; -pub use euclid; - -#[macro_use] -extern crate bitflags; -#[cfg(feature = "nightly")] -extern crate core; -#[macro_use] -extern crate malloc_size_of_derive; -#[macro_use] -extern crate serde_derive; - -use malloc_size_of; -use peek_poke; - -pub mod channel; -mod color; -mod display_item; -mod display_item_cache; -mod display_list; -mod font; -mod gradient_builder; -mod image; -pub mod units; - -pub use crate::color::*; -pub use crate::display_item::*; -pub use crate::display_item_cache::DisplayItemCache; -pub use crate::display_list::*; -pub use crate::font::*; -pub use crate::gradient_builder::*; -pub use crate::image::*; - -use crate::units::*; -use crate::channel::Receiver; -use std::marker::PhantomData; -use std::sync::Arc; -use std::os::raw::c_void; -use peek_poke::PeekPoke; - -/// Width and height in device pixels of image tiles. -pub type TileSize = u16; - -/// Various settings that the caller can select based on desired tradeoffs -/// between rendering quality and performance / power usage. -#[derive(Copy, Clone, Deserialize, Serialize)] -pub struct QualitySettings { - /// If true, disable creating separate picture cache slices when the - /// scroll root changes. This gives maximum opportunity to find an - /// opaque background, which enables subpixel AA. However, it is - /// usually significantly more expensive to render when scrolling. - pub force_subpixel_aa_where_possible: bool, -} - -impl Default for QualitySettings { - fn default() -> Self { - QualitySettings { - // Prefer performance over maximum subpixel AA quality, since WR - // already enables subpixel AA in more situations than other browsers. - force_subpixel_aa_where_possible: false, - } - } -} - -/// An epoch identifies the state of a pipeline in time. -/// -/// This is mostly used as a synchronization mechanism to observe how/when particular pipeline -/// updates propagate through WebRender and are applied at various stages. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] -pub struct Epoch(pub u32); - -impl Epoch { - /// Magic invalid epoch value. - pub fn invalid() -> Epoch { - Epoch(u32::MAX) - } -} - -/// ID namespaces uniquely identify different users of WebRender's API. -/// -/// For example in Gecko each content process uses a separate id namespace. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, PeekPoke)] -#[derive(Deserialize, Serialize)] -pub struct IdNamespace(pub u32); - -/// A key uniquely identifying a WebRender document. -/// -/// Instances can manage one or several documents (using the same render backend thread). -/// Each document will internally correspond to a single scene, and scenes are made of -/// one or several pipelines. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct DocumentId { - /// - pub namespace_id: IdNamespace, - /// - pub id: u32, -} - -impl DocumentId { - /// - pub fn new(namespace_id: IdNamespace, id: u32) -> Self { - DocumentId { - namespace_id, - id, - } - } - - /// - pub const INVALID: DocumentId = DocumentId { namespace_id: IdNamespace(0), id: 0 }; -} - -/// This type carries no valuable semantics for WR. However, it reflects the fact that -/// clients (Servo) may generate pipelines by different semi-independent sources. -/// These pipelines still belong to the same `IdNamespace` and the same `DocumentId`. -/// Having this extra Id field enables them to generate `PipelineId` without collision. -pub type PipelineSourceId = u32; - -/// From the point of view of WR, `PipelineId` is completely opaque and generic as long as -/// it's clonable, serializable, comparable, and hashable. -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct PipelineId(pub PipelineSourceId, pub u32); - -impl Default for PipelineId { - fn default() -> Self { - PipelineId::dummy() - } -} - -impl PipelineId { - /// - pub fn dummy() -> Self { - PipelineId(!0, !0) - } -} - - -/// An opaque pointer-sized value. -#[repr(C)] -#[derive(Clone)] -pub struct ExternalEvent { - raw: usize, -} - -unsafe impl Send for ExternalEvent {} - -impl ExternalEvent { - /// Creates the event from an opaque pointer-sized value. - pub fn from_raw(raw: usize) -> Self { - ExternalEvent { raw } - } - /// Consumes self to make it obvious that the event should be forwarded only once. - pub fn unwrap(self) -> usize { - self.raw - } -} - -/// Describe whether or not scrolling should be clamped by the content bounds. -#[derive(Clone, Deserialize, Serialize)] -pub enum ScrollClamping { - /// - ToContentBounds, - /// - NoClamping, -} - -/// A handler to integrate WebRender with the thread that contains the `Renderer`. -pub trait RenderNotifier: Send { - /// - fn clone(&self) -> Box<dyn RenderNotifier>; - /// Wake the thread containing the `Renderer` up (after updates have been put - /// in the renderer's queue). - fn wake_up( - &self, - composite_needed: bool, - ); - /// Notify the thread containing the `Renderer` that a new frame is ready. - fn new_frame_ready(&self, _: DocumentId, scrolled: bool, composite_needed: bool, render_time_ns: Option<u64>); - /// A Gecko-specific notification mechanism to get some code executed on the - /// `Renderer`'s thread, mostly replaced by `NotificationHandler`. You should - /// probably use the latter instead. - fn external_event(&self, _evt: ExternalEvent) { - unimplemented!() - } - /// Notify the thread containing the `Renderer` that the render backend has been - /// shut down. - fn shut_down(&self) {} -} - -/// A stage of the rendering pipeline. -#[repr(u32)] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Checkpoint { - /// - SceneBuilt, - /// - FrameBuilt, - /// - FrameTexturesUpdated, - /// - FrameRendered, - /// NotificationRequests get notified with this if they get dropped without having been - /// notified. This provides the guarantee that if a request is created it will get notified. - TransactionDropped, -} - -/// A handler to notify when a transaction reaches certain stages of the rendering -/// pipeline. -pub trait NotificationHandler : Send + Sync { - /// Entry point of the handler to implement. Invoked by WebRender. - fn notify(&self, when: Checkpoint); -} - -/// A request to notify a handler when the transaction reaches certain stages of the -/// rendering pipeline. -/// -/// The request is guaranteed to be notified once and only once, even if the transaction -/// is dropped before the requested check-point. -pub struct NotificationRequest { - handler: Option<Box<dyn NotificationHandler>>, - when: Checkpoint, -} - -impl NotificationRequest { - /// Constructor. - pub fn new(when: Checkpoint, handler: Box<dyn NotificationHandler>) -> Self { - NotificationRequest { - handler: Some(handler), - when, - } - } - - /// The specified stage at which point the handler should be notified. - pub fn when(&self) -> Checkpoint { self.when } - - /// Called by WebRender at specified stages to notify the registered handler. - pub fn notify(mut self) { - if let Some(handler) = self.handler.take() { - handler.notify(self.when); - } - } -} - -/// An object that can perform hit-testing without doing synchronous queries to -/// the RenderBackendThread. -pub trait ApiHitTester: Send + Sync { - /// Does a hit test on display items in the specified document, at the given - /// point. If a pipeline_id is specified, it is used to further restrict the - /// hit results so that only items inside that pipeline are matched. The vector - /// of hit results will contain all display items that match, ordered from - /// front to back. - fn hit_test(&self, pipeline_id: Option<PipelineId>, point: WorldPoint, flags: HitTestFlags) -> HitTestResult; -} - -/// A hit tester requested to the render backend thread but not necessarily ready yet. -/// -/// The request should be resolved as late as possible to reduce the likelihood of blocking. -pub struct HitTesterRequest { - #[doc(hidden)] - pub rx: Receiver<Arc<dyn ApiHitTester>>, -} - -impl HitTesterRequest { - /// Block until the hit tester is available and return it, consuming teh request. - pub fn resolve(self) -> Arc<dyn ApiHitTester> { - self.rx.recv().unwrap() - } -} - -/// Describe an item that matched a hit-test query. -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -pub struct HitTestItem { - /// The pipeline that the display item that was hit belongs to. - pub pipeline: PipelineId, - - /// The tag of the hit display item. - pub tag: ItemTag, - - /// The hit point in the coordinate space of the "viewport" of the display item. The - /// viewport is the scroll node formed by the root reference frame of the display item's - /// pipeline. - pub point_in_viewport: LayoutPoint, - - /// The coordinates of the original hit test point relative to the origin of this item. - /// This is useful for calculating things like text offsets in the client. - pub point_relative_to_item: LayoutPoint, -} - -/// Returned by `RenderApi::hit_test`. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct HitTestResult { - /// List of items that are match the hit-test query. - pub items: Vec<HitTestItem>, -} - -bitflags! { - #[derive(Deserialize, MallocSizeOf, Serialize)] - /// - pub struct HitTestFlags: u8 { - /// - const FIND_ALL = 0b00000001; - /// - const POINT_RELATIVE_TO_PIPELINE_VIEWPORT = 0b00000010; - } -} - -impl Drop for NotificationRequest { - fn drop(&mut self) { - if let Some(ref mut handler) = self.handler { - handler.notify(Checkpoint::TransactionDropped); - } - } -} - -// This Clone impl yields an "empty" request because we don't want the requests -// to be notified twice so the request is owned by only one of the API messages -// (the original one) after the clone. -// This works in practice because the notifications requests are used for -// synchronization so we don't need to include them in the recording mechanism -// in wrench that clones the messages. -impl Clone for NotificationRequest { - fn clone(&self) -> Self { - NotificationRequest { - when: self.when, - handler: None, - } - } -} - - -/// A key to identify an animated property binding. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] -pub struct PropertyBindingId { - pub namespace: IdNamespace, - pub uid: u32, -} - -impl PropertyBindingId { - /// Constructor. - pub fn new(value: u64) -> Self { - PropertyBindingId { - namespace: IdNamespace((value >> 32) as u32), - uid: value as u32, - } - } -} - -/// A unique key that is used for connecting animated property -/// values to bindings in the display list. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub struct PropertyBindingKey<T> { - /// - pub id: PropertyBindingId, - #[doc(hidden)] - pub _phantom: PhantomData<T>, -} - -/// Construct a property value from a given key and value. -impl<T: Copy> PropertyBindingKey<T> { - /// - pub fn with(self, value: T) -> PropertyValue<T> { - PropertyValue { key: self, value } - } -} - -impl<T> PropertyBindingKey<T> { - /// Constructor. - pub fn new(value: u64) -> Self { - PropertyBindingKey { - id: PropertyBindingId::new(value), - _phantom: PhantomData, - } - } -} - -/// A binding property can either be a specific value -/// (the normal, non-animated case) or point to a binding location -/// to fetch the current value from. -/// Note that Binding has also a non-animated value, the value is -/// used for the case where the animation is still in-delay phase -/// (i.e. the animation doesn't produce any animation values). -#[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] -pub enum PropertyBinding<T> { - /// Non-animated value. - Value(T), - /// Animated binding. - Binding(PropertyBindingKey<T>, T), -} - -impl<T: Default> Default for PropertyBinding<T> { - fn default() -> Self { - PropertyBinding::Value(Default::default()) - } -} - -impl<T> From<T> for PropertyBinding<T> { - fn from(value: T) -> PropertyBinding<T> { - PropertyBinding::Value(value) - } -} - -impl From<PropertyBindingKey<ColorF>> for PropertyBindingKey<ColorU> { - fn from(key: PropertyBindingKey<ColorF>) -> PropertyBindingKey<ColorU> { - PropertyBindingKey { - id: key.id.clone(), - _phantom: PhantomData, - } - } -} - -impl From<PropertyBindingKey<ColorU>> for PropertyBindingKey<ColorF> { - fn from(key: PropertyBindingKey<ColorU>) -> PropertyBindingKey<ColorF> { - PropertyBindingKey { - id: key.id.clone(), - _phantom: PhantomData, - } - } -} - -impl From<PropertyBinding<ColorF>> for PropertyBinding<ColorU> { - fn from(value: PropertyBinding<ColorF>) -> PropertyBinding<ColorU> { - match value { - PropertyBinding::Value(value) => PropertyBinding::Value(value.into()), - PropertyBinding::Binding(k, v) => { - PropertyBinding::Binding(k.into(), v.into()) - } - } - } -} - -impl From<PropertyBinding<ColorU>> for PropertyBinding<ColorF> { - fn from(value: PropertyBinding<ColorU>) -> PropertyBinding<ColorF> { - match value { - PropertyBinding::Value(value) => PropertyBinding::Value(value.into()), - PropertyBinding::Binding(k, v) => { - PropertyBinding::Binding(k.into(), v.into()) - } - } - } -} - -/// The current value of an animated property. This is -/// supplied by the calling code. -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)] -pub struct PropertyValue<T> { - /// - pub key: PropertyBindingKey<T>, - /// - pub value: T, -} - -/// When using `generate_frame()`, a list of `PropertyValue` structures -/// can optionally be supplied to provide the current value of any -/// animated properties. -#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Default)] -pub struct DynamicProperties { - /// - pub transforms: Vec<PropertyValue<LayoutTransform>>, - /// opacity - pub floats: Vec<PropertyValue<f32>>, - /// background color - pub colors: Vec<PropertyValue<ColorF>>, -} - -/// A C function that takes a pointer to a heap allocation and returns its size. -/// -/// This is borrowed from the malloc_size_of crate, upon which we want to avoid -/// a dependency from WebRender. -pub type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize; - -bitflags! { - /// Flags to enable/disable various builtin debugging tools. - #[repr(C)] - #[derive(Default, Deserialize, MallocSizeOf, Serialize)] - pub struct DebugFlags: u32 { - /// Display the frame profiler on screen. - const PROFILER_DBG = 1 << 0; - /// Display intermediate render targets on screen. - const RENDER_TARGET_DBG = 1 << 1; - /// Display all texture cache pages on screen. - const TEXTURE_CACHE_DBG = 1 << 2; - /// Display GPU timing results. - const GPU_TIME_QUERIES = 1 << 3; - /// Query the number of pixels that pass the depth test divided and show it - /// in the profiler as a percentage of the number of pixels in the screen - /// (window width times height). - const GPU_SAMPLE_QUERIES = 1 << 4; - /// Render each quad with their own draw call. - /// - /// Terrible for performance but can help with understanding the drawing - /// order when inspecting renderdoc or apitrace recordings. - const DISABLE_BATCHING = 1 << 5; - /// Display the pipeline epochs. - const EPOCHS = 1 << 6; - /// Print driver messages to stdout. - const ECHO_DRIVER_MESSAGES = 1 << 7; - /// Show an overlay displaying overdraw amount. - const SHOW_OVERDRAW = 1 << 8; - /// Display the contents of GPU cache. - const GPU_CACHE_DBG = 1 << 9; - /// Clear evicted parts of the texture cache for debugging purposes. - const TEXTURE_CACHE_DBG_CLEAR_EVICTED = 1 << 10; - /// Show picture caching debug overlay - const PICTURE_CACHING_DBG = 1 << 11; - /// Highlight all primitives with colors based on kind. - const PRIMITIVE_DBG = 1 << 12; - /// Draw a zoom widget showing part of the framebuffer zoomed in. - const ZOOM_DBG = 1 << 13; - /// Scale the debug renderer down for a smaller screen. This will disrupt - /// any mapping between debug display items and page content, so shouldn't - /// be used with overlays like the picture caching or primitive display. - const SMALL_SCREEN = 1 << 14; - /// Disable various bits of the WebRender pipeline, to help narrow - /// down where slowness might be coming from. - const DISABLE_OPAQUE_PASS = 1 << 15; - /// - const DISABLE_ALPHA_PASS = 1 << 16; - /// - const DISABLE_CLIP_MASKS = 1 << 17; - /// - const DISABLE_TEXT_PRIMS = 1 << 18; - /// - const DISABLE_GRADIENT_PRIMS = 1 << 19; - /// - const OBSCURE_IMAGES = 1 << 20; - /// Taint the transparent area of the glyphs with a random opacity to easily - /// see when glyphs are re-rasterized. - const GLYPH_FLASHING = 1 << 21; - /// The profiler only displays information that is out of the ordinary. - const SMART_PROFILER = 1 << 22; - /// If set, dump picture cache invalidation debug to console. - const INVALIDATION_DBG = 1 << 23; - /// Log tile cache to memory for later saving as part of wr-capture - const TILE_CACHE_LOGGING_DBG = 1 << 24; - /// Collect and dump profiler statistics to captures. - const PROFILER_CAPTURE = (1 as u32) << 25; // need "as u32" until we have cbindgen#556 - /// Invalidate picture tiles every frames (useful when inspecting GPU work in external tools). - const FORCE_PICTURE_INVALIDATION = (1 as u32) << 26; - const USE_BATCHED_TEXTURE_UPLOADS = (1 as u32) << 27; - const USE_DRAW_CALLS_FOR_TEXTURE_COPY = (1 as u32) << 28; - } -} - -/// Information specific to a primitive type that -/// uniquely identifies a primitive template by key. -#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash, Serialize, Deserialize)] -pub enum PrimitiveKeyKind { - /// Clear an existing rect, used for special effects on some platforms. - Clear, - /// - Rectangle { - /// - color: PropertyBinding<ColorU>, - }, -} - -/// -#[derive(Clone)] -pub struct ScrollNodeState { - /// - pub id: ExternalScrollId, - /// - pub scroll_offset: LayoutVector2D, -} - -/// -#[derive(Clone, Copy, Debug)] -pub enum ScrollLocation { - /// Scroll by a certain amount. - Delta(LayoutVector2D), - /// Scroll to very top of element. - Start, - /// Scroll to very bottom of element. - End, -} - -/// Represents a zoom factor. -#[derive(Clone, Copy, Debug)] -pub struct ZoomFactor(f32); - -impl ZoomFactor { - /// Construct a new zoom factor. - pub fn new(scale: f32) -> Self { - ZoomFactor(scale) - } - - /// Get the zoom factor as an untyped float. - pub fn get(self) -> f32 { - self.0 - } -} - -/// Crash annotations included in crash reports. -#[repr(C)] -#[derive(Clone, Copy)] -pub enum CrashAnnotation { - CompileShader = 0, - DrawShader = 1, -} - -/// Handler to expose support for annotating crash reports. -pub trait CrashAnnotator : Send { - fn set(&self, annotation: CrashAnnotation, value: &std::ffi::CStr); - fn clear(&self, annotation: CrashAnnotation); - fn box_clone(&self) -> Box<dyn CrashAnnotator>; -} - -impl Clone for Box<dyn CrashAnnotator> { - fn clone(&self) -> Box<dyn CrashAnnotator> { - self.box_clone() - } -} - -/// Guard to add a crash annotation at creation, and clear it at destruction. -pub struct CrashAnnotatorGuard<'a> { - annotator: &'a Option<Box<dyn CrashAnnotator>>, - annotation: CrashAnnotation, -} - -impl<'a> CrashAnnotatorGuard<'a> { - pub fn new( - annotator: &'a Option<Box<dyn CrashAnnotator>>, - annotation: CrashAnnotation, - value: &std::ffi::CStr, - ) -> Self { - if let Some(ref annotator) = annotator { - annotator.set(annotation, value); - } - Self { - annotator, - annotation, - } - } -} - -impl<'a> Drop for CrashAnnotatorGuard<'a> { - fn drop(&mut self) { - if let Some(ref annotator) = self.annotator { - annotator.clear(self.annotation); - } - } -} diff --git a/third_party/webrender/webrender_api/src/units.rs b/third_party/webrender/webrender_api/src/units.rs deleted file mode 100644 index 5ec6a80e920..00000000000 --- a/third_party/webrender/webrender_api/src/units.rs +++ /dev/null @@ -1,325 +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 http://mozilla.org/MPL/2.0/. */ - -//! A collection of coordinate spaces and their corresponding Point, Size and Rect types. -//! -//! Physical pixels take into account the device pixel ratio and their dimensions tend -//! to correspond to the allocated size of resources in memory, while logical pixels -//! don't have the device pixel ratio applied which means they are agnostic to the usage -//! of hidpi screens and the like. -//! -//! The terms "layer" and "stacking context" can be used interchangeably -//! in the context of coordinate systems. - -pub use app_units::Au; -use euclid::{Length, Rect, Scale, Size2D, Transform3D, Translation2D}; -use euclid::{Point2D, Point3D, Vector2D, Vector3D, SideOffsets2D, Box2D}; -use euclid::HomogeneousVector; -use peek_poke::PeekPoke; -// local imports -use crate::image::DirtyRect; - -/// Geometry in the coordinate system of the render target (screen or intermediate -/// surface) in physical pixels. -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] -pub struct DevicePixel; - -pub type DeviceIntRect = Rect<i32, DevicePixel>; -pub type DeviceIntPoint = Point2D<i32, DevicePixel>; -pub type DeviceIntSize = Size2D<i32, DevicePixel>; -pub type DeviceIntLength = Length<i32, DevicePixel>; -pub type DeviceIntSideOffsets = SideOffsets2D<i32, DevicePixel>; - -pub type DeviceRect = Rect<f32, DevicePixel>; -pub type DeviceBox2D = Box2D<f32, DevicePixel>; -pub type DevicePoint = Point2D<f32, DevicePixel>; -pub type DeviceVector2D = Vector2D<f32, DevicePixel>; -pub type DeviceSize = Size2D<f32, DevicePixel>; -pub type DeviceHomogeneousVector = HomogeneousVector<f32, DevicePixel>; - -/// Geometry in the coordinate system of the framebuffer in physical pixels. -/// It's Y-flipped comparing to DevicePixel. -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] -pub struct FramebufferPixel; - -pub type FramebufferIntPoint = Point2D<i32, FramebufferPixel>; -pub type FramebufferIntSize = Size2D<i32, FramebufferPixel>; -pub type FramebufferIntRect = Rect<i32, FramebufferPixel>; - -/// Geometry in the coordinate system of a Picture (intermediate -/// surface) in physical pixels. -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct PicturePixel; - -pub type PictureIntRect = Rect<i32, PicturePixel>; -pub type PictureIntPoint = Point2D<i32, PicturePixel>; -pub type PictureIntSize = Size2D<i32, PicturePixel>; -pub type PictureRect = Rect<f32, PicturePixel>; -pub type PicturePoint = Point2D<f32, PicturePixel>; -pub type PictureSize = Size2D<f32, PicturePixel>; -pub type PicturePoint3D = Point3D<f32, PicturePixel>; -pub type PictureVector2D = Vector2D<f32, PicturePixel>; -pub type PictureVector3D = Vector3D<f32, PicturePixel>; -pub type PictureBox2D = Box2D<f32, PicturePixel>; - -/// Geometry gets rasterized in a given root coordinate space. This -/// is often the root spatial node (world space), but may be a local -/// space for a variety of reasons (e.g. perspective). -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct RasterPixel; - -pub type RasterIntRect = Rect<i32, RasterPixel>; -pub type RasterIntPoint = Point2D<i32, RasterPixel>; -pub type RasterIntSize = Size2D<i32, RasterPixel>; -pub type RasterRect = Rect<f32, RasterPixel>; -pub type RasterPoint = Point2D<f32, RasterPixel>; -pub type RasterSize = Size2D<f32, RasterPixel>; -pub type RasterPoint3D = Point3D<f32, RasterPixel>; -pub type RasterVector2D = Vector2D<f32, RasterPixel>; -pub type RasterVector3D = Vector3D<f32, RasterPixel>; - -/// Geometry in a stacking context's local coordinate space (logical pixels). -#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize, PeekPoke)] -pub struct LayoutPixel; - -pub type LayoutRect = Rect<f32, LayoutPixel>; -pub type LayoutPoint = Point2D<f32, LayoutPixel>; -pub type LayoutPoint3D = Point3D<f32, LayoutPixel>; -pub type LayoutVector2D = Vector2D<f32, LayoutPixel>; -pub type LayoutVector3D = Vector3D<f32, LayoutPixel>; -pub type LayoutSize = Size2D<f32, LayoutPixel>; -pub type LayoutSideOffsets = SideOffsets2D<f32, LayoutPixel>; - -pub type LayoutIntRect = Rect<i32, LayoutPixel>; -pub type LayoutIntPoint = Point2D<i32, LayoutPixel>; -pub type LayoutIntSize = Size2D<i32, LayoutPixel>; - -/// Geometry in the document's coordinate space (logical pixels). -#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd)] -pub struct WorldPixel; - -pub type WorldRect = Rect<f32, WorldPixel>; -pub type WorldPoint = Point2D<f32, WorldPixel>; -pub type WorldSize = Size2D<f32, WorldPixel>; -pub type WorldPoint3D = Point3D<f32, WorldPixel>; -pub type WorldVector2D = Vector2D<f32, WorldPixel>; -pub type WorldVector3D = Vector3D<f32, WorldPixel>; - -/// Offset in number of tiles. -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct Tiles; -pub type TileOffset = Point2D<i32, Tiles>; -pub type TileRange = Rect<i32, Tiles>; - -/// Scaling ratio from world pixels to device pixels. -pub type DevicePixelScale = Scale<f32, WorldPixel, DevicePixel>; -/// Scaling ratio from layout to world. Used for cases where we know the layout -/// is in world space, or specifically want to treat it this way. -pub type LayoutToWorldScale = Scale<f32, LayoutPixel, WorldPixel>; -/// A complete scaling ratio from layout space to device pixel space. -pub type LayoutToDeviceScale = Scale<f32, LayoutPixel, DevicePixel>; - -pub type LayoutTransform = Transform3D<f32, LayoutPixel, LayoutPixel>; -pub type LayoutToWorldTransform = Transform3D<f32, LayoutPixel, WorldPixel>; -pub type WorldToLayoutTransform = Transform3D<f32, WorldPixel, LayoutPixel>; - -pub type LayoutToPictureTransform = Transform3D<f32, LayoutPixel, PicturePixel>; -pub type PictureToLayoutTransform = Transform3D<f32, PicturePixel, LayoutPixel>; - -pub type LayoutToRasterTransform = Transform3D<f32, LayoutPixel, RasterPixel>; -pub type RasterToLayoutTransform = Transform3D<f32, RasterPixel, LayoutPixel>; - -pub type PictureToRasterTransform = Transform3D<f32, PicturePixel, RasterPixel>; -pub type RasterToPictureTransform = Transform3D<f32, RasterPixel, PicturePixel>; - -// Fixed position coordinates, to avoid float precision errors. -pub type LayoutPointAu = Point2D<Au, LayoutPixel>; -pub type LayoutRectAu = Rect<Au, LayoutPixel>; -pub type LayoutSizeAu = Size2D<Au, LayoutPixel>; -pub type LayoutVector2DAu = Vector2D<Au, LayoutPixel>; -pub type LayoutSideOffsetsAu = SideOffsets2D<Au, LayoutPixel>; - -pub type ImageDirtyRect = DirtyRect<i32, DevicePixel>; -pub type BlobDirtyRect = DirtyRect<i32, LayoutPixel>; - -pub type BlobToDeviceTranslation = Translation2D<i32, LayoutPixel, DevicePixel>; - -/// Stores two coordinates in texel space. The coordinates -/// are stored in texel coordinates because the texture atlas -/// may grow. Storing them as texel coords and normalizing -/// the UVs in the vertex shader means nothing needs to be -/// updated on the CPU when the texture size changes. -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct TexelRect { - pub uv0: DevicePoint, - pub uv1: DevicePoint, -} - -impl TexelRect { - pub fn new(u0: f32, v0: f32, u1: f32, v1: f32) -> Self { - TexelRect { - uv0: DevicePoint::new(u0, v0), - uv1: DevicePoint::new(u1, v1), - } - } - - pub fn invalid() -> Self { - TexelRect { - uv0: DevicePoint::new(-1.0, -1.0), - uv1: DevicePoint::new(-1.0, -1.0), - } - } -} - -impl Into<TexelRect> for DeviceIntRect { - fn into(self) -> TexelRect { - TexelRect { - uv0: self.min().to_f32(), - uv1: self.max().to_f32(), - } - } -} - -const MAX_AU_FLOAT: f32 = 1.0e6; - -pub trait AuHelpers<T> { - fn from_au(data: T) -> Self; - fn to_au(&self) -> T; -} - -impl AuHelpers<LayoutSizeAu> for LayoutSize { - fn from_au(size: LayoutSizeAu) -> Self { - LayoutSize::new( - size.width.to_f32_px(), - size.height.to_f32_px(), - ) - } - - fn to_au(&self) -> LayoutSizeAu { - let width = self.width.min(2.0 * MAX_AU_FLOAT); - let height = self.height.min(2.0 * MAX_AU_FLOAT); - - LayoutSizeAu::new( - Au::from_f32_px(width), - Au::from_f32_px(height), - ) - } -} - -impl AuHelpers<LayoutVector2DAu> for LayoutVector2D { - fn from_au(size: LayoutVector2DAu) -> Self { - LayoutVector2D::new( - size.x.to_f32_px(), - size.y.to_f32_px(), - ) - } - - fn to_au(&self) -> LayoutVector2DAu { - LayoutVector2DAu::new( - Au::from_f32_px(self.x), - Au::from_f32_px(self.y), - ) - } -} - -impl AuHelpers<LayoutPointAu> for LayoutPoint { - fn from_au(point: LayoutPointAu) -> Self { - LayoutPoint::new( - point.x.to_f32_px(), - point.y.to_f32_px(), - ) - } - - fn to_au(&self) -> LayoutPointAu { - let x = self.x.min(MAX_AU_FLOAT).max(-MAX_AU_FLOAT); - let y = self.y.min(MAX_AU_FLOAT).max(-MAX_AU_FLOAT); - - LayoutPointAu::new( - Au::from_f32_px(x), - Au::from_f32_px(y), - ) - } -} - -impl AuHelpers<LayoutRectAu> for LayoutRect { - fn from_au(rect: LayoutRectAu) -> Self { - LayoutRect::new( - LayoutPoint::from_au(rect.origin), - LayoutSize::from_au(rect.size), - ) - } - - fn to_au(&self) -> LayoutRectAu { - LayoutRectAu::new( - self.origin.to_au(), - self.size.to_au(), - ) - } -} - -impl AuHelpers<LayoutSideOffsetsAu> for LayoutSideOffsets { - fn from_au(offsets: LayoutSideOffsetsAu) -> Self { - LayoutSideOffsets::new( - offsets.top.to_f32_px(), - offsets.right.to_f32_px(), - offsets.bottom.to_f32_px(), - offsets.left.to_f32_px(), - ) - } - - fn to_au(&self) -> LayoutSideOffsetsAu { - LayoutSideOffsetsAu::new( - Au::from_f32_px(self.top), - Au::from_f32_px(self.right), - Au::from_f32_px(self.bottom), - Au::from_f32_px(self.left), - ) - } -} - -pub trait RectExt { - type Point; - fn top_left(&self) -> Self::Point; - fn top_right(&self) -> Self::Point; - fn bottom_left(&self) -> Self::Point; - fn bottom_right(&self) -> Self::Point; -} - -impl<U> RectExt for Rect<f32, U> { - type Point = Point2D<f32, U>; - fn top_left(&self) -> Self::Point { - self.min() - } - fn top_right(&self) -> Self::Point { - Point2D::new(self.max_x(), self.min_y()) - } - fn bottom_left(&self) -> Self::Point { - Point2D::new(self.min_x(), self.max_y()) - } - fn bottom_right(&self) -> Self::Point { - self.max() - } -} - -// A few helpers to convert to cast between coordinate spaces that are often equivalent. - -#[inline] -pub fn layout_rect_as_picture_rect(layout_rect: &LayoutRect) -> PictureRect { - layout_rect.cast_unit() -} - -#[inline] -pub fn layout_vector_as_picture_vector(layout_vector: LayoutVector2D) -> PictureVector2D { - layout_vector.cast_unit() -} - -#[inline] -pub fn device_size_as_framebuffer_size(framebuffer_size: DeviceIntSize) -> FramebufferIntSize { - framebuffer_size.cast_unit() -} - -#[inline] -pub fn device_rect_as_framebuffer_rect(framebuffer_rect: &DeviceIntRect) -> FramebufferIntRect { - framebuffer_rect.cast_unit() -} |