diff options
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() -} |