Skip to main content

webrender_api/
display_item.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use euclid::{SideOffsets2D, Angle};
6use peek_poke::PeekPoke;
7use std::ops::Not;
8// local imports
9use crate::{font, SnapshotImageKey};
10use crate::{APZScrollGeneration, HasScrollLinkedEffect, PipelineId, PropertyBinding};
11use crate::serde::{Serialize, Deserialize};
12use crate::color::ColorF;
13use crate::image::{ColorDepth, ImageKey};
14use crate::units::*;
15use std::hash::{Hash, Hasher};
16
17// ******************************************************************
18// * NOTE: some of these structs have an "IMPLICIT" comment.        *
19// * This indicates that the BuiltDisplayList will have serialized  *
20// * a list of values nearby that this item consumes. The traversal *
21// * iterator should handle finding these. DebugDisplayItem should  *
22// * make them explicit.                                            *
23// ******************************************************************
24
25/// A tag that can be used to identify items during hit testing. If the tag
26/// is missing then the item doesn't take part in hit testing at all. This
27/// is composed of two numbers. In Servo, the first is an identifier while the
28/// second is used to select the cursor that should be used during mouse
29/// movement. In Gecko, the first is a scrollframe identifier, while the second
30/// is used to store various flags that APZ needs to properly process input
31/// events.
32pub type ItemTag = (u64, u16);
33
34#[repr(C)]
35#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)]
36pub struct PrimitiveFlags(u8);
37
38bitflags! {
39    impl PrimitiveFlags: u8 {
40        /// The CSS backface-visibility property (yes, it can be really granular)
41        const IS_BACKFACE_VISIBLE = 1 << 0;
42        /// If set, this primitive represents a scroll bar container
43        const IS_SCROLLBAR_CONTAINER = 1 << 1;
44        /// This is used as a performance hint - this primitive may be promoted to a native
45        /// compositor surface under certain (implementation specific) conditions. This
46        /// is typically used for large videos, and canvas elements.
47        const PREFER_COMPOSITOR_SURFACE = 1 << 2;
48        /// If set, this primitive can be passed directly to the compositor via its
49        /// ExternalImageId, and the compositor will use the native image directly.
50        /// Used as a further extension on top of PREFER_COMPOSITOR_SURFACE.
51        const SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE = 1 << 3;
52        /// This flags disables snapping and forces anti-aliasing even if the primitive is axis-aligned.
53        const ANTIALISED = 1 << 4;
54        /// If true, this primitive is used as a background for checkerboarding
55        const CHECKERBOARD_BACKGROUND = 1 << 5;
56    }
57}
58
59impl core::fmt::Debug for PrimitiveFlags {
60    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
61        if self.is_empty() {
62            write!(f, "{:#x}", Self::empty().bits())
63        } else {
64            bitflags::parser::to_writer(self, f)
65        }
66    }
67}
68
69impl Default for PrimitiveFlags {
70    fn default() -> Self {
71        PrimitiveFlags::IS_BACKFACE_VISIBLE
72    }
73}
74
75/// A grouping of fields a lot of display items need, just to avoid
76/// repeating these over and over in this file.
77#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
78pub struct CommonItemProperties {
79    /// Bounds of the display item to clip to. Many items are logically
80    /// infinite, and rely on this clip_rect to define their bounds
81    /// (solid colors, background-images, gradients, etc).
82    pub clip_rect: LayoutRect,
83    /// Additional clips
84    pub clip_chain_id: ClipChainId,
85    /// The coordinate-space the item is in (yes, it can be really granular)
86    pub spatial_id: SpatialId,
87    /// Various flags describing properties of this primitive.
88    pub flags: PrimitiveFlags,
89}
90
91impl CommonItemProperties {
92    /// Convenience for tests.
93    pub fn new(
94        clip_rect: LayoutRect,
95        space_and_clip: SpaceAndClipInfo,
96    ) -> Self {
97        Self {
98            clip_rect,
99            spatial_id: space_and_clip.spatial_id,
100            clip_chain_id: space_and_clip.clip_chain_id,
101            flags: PrimitiveFlags::default(),
102        }
103    }
104}
105
106/// Per-primitive information about the nodes in the clip tree and
107/// the spatial tree that the primitive belongs to.
108///
109/// Note: this is a separate struct from `PrimitiveInfo` because
110/// it needs indirectional mapping during the DL flattening phase,
111/// turning into `ScrollNodeAndClipChain`.
112#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
113pub struct SpaceAndClipInfo {
114    pub spatial_id: SpatialId,
115    pub clip_chain_id: ClipChainId,
116}
117
118impl SpaceAndClipInfo {
119    /// Create a new space/clip info associated with the root
120    /// scroll frame.
121    pub fn root_scroll(pipeline_id: PipelineId) -> Self {
122        SpaceAndClipInfo {
123            spatial_id: SpatialId::root_scroll_node(pipeline_id),
124            clip_chain_id: ClipChainId::INVALID,
125        }
126    }
127}
128
129#[repr(u8)]
130#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
131pub enum SpatialTreeItem {
132    ScrollFrame(ScrollFrameDescriptor),
133    ReferenceFrame(ReferenceFrameDescriptor),
134    StickyFrame(StickyFrameDescriptor),
135    Invalid,
136}
137
138#[repr(u8)]
139#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
140pub enum DisplayItem {
141    // These are the "real content" display items
142    Rectangle(RectangleDisplayItem),
143    HitTest(HitTestDisplayItem),
144    Text(TextDisplayItem),
145    Line(LineDisplayItem),
146    Border(BorderDisplayItem),
147    BoxShadow(BoxShadowDisplayItem),
148    PushShadow(PushShadowDisplayItem),
149    Gradient(GradientDisplayItem),
150    RadialGradient(RadialGradientDisplayItem),
151    ConicGradient(ConicGradientDisplayItem),
152    Image(ImageDisplayItem),
153    RepeatingImage(RepeatingImageDisplayItem),
154    YuvImage(YuvImageDisplayItem),
155    BackdropFilter(BackdropFilterDisplayItem),
156
157    // Clips
158    RectClip(RectClipDisplayItem),
159    RoundedRectClip(RoundedRectClipDisplayItem),
160    ImageMaskClip(ImageMaskClipDisplayItem),
161    ClipChain(ClipChainItem),
162
163    // Spaces and Frames that content can be scoped under.
164    Iframe(IframeDisplayItem),
165    PushReferenceFrame(ReferenceFrameDisplayListItem),
166    PushStackingContext(PushStackingContextDisplayItem),
167
168    // These marker items indicate an array of data follows, to be used for the
169    // next non-marker item.
170    SetGradientStops,
171    SetFilterOps,
172    SetFilterData,
173    SetPoints,
174
175    // These marker items terminate a scope introduced by a previous item.
176    PopReferenceFrame,
177    PopStackingContext,
178    PopAllShadows,
179
180    // For debugging purposes.
181    DebugMarker(u32),
182}
183
184/// This is a "complete" version of the DisplayItem, with all implicit trailing
185/// arrays included, for debug serialization (captures).
186#[cfg(any(feature = "serialize", feature = "deserialize"))]
187#[cfg_attr(feature = "serialize", derive(Serialize))]
188#[cfg_attr(feature = "deserialize", derive(Deserialize))]
189pub enum DebugDisplayItem {
190    Rectangle(RectangleDisplayItem),
191    HitTest(HitTestDisplayItem),
192    Text(TextDisplayItem, Vec<font::GlyphInstance>),
193    Line(LineDisplayItem),
194    Border(BorderDisplayItem),
195    BoxShadow(BoxShadowDisplayItem),
196    PushShadow(PushShadowDisplayItem),
197    Gradient(GradientDisplayItem),
198    RadialGradient(RadialGradientDisplayItem),
199    ConicGradient(ConicGradientDisplayItem),
200    Image(ImageDisplayItem),
201    RepeatingImage(RepeatingImageDisplayItem),
202    YuvImage(YuvImageDisplayItem),
203    BackdropFilter(BackdropFilterDisplayItem),
204
205    ImageMaskClip(ImageMaskClipDisplayItem),
206    RoundedRectClip(RoundedRectClipDisplayItem),
207    RectClip(RectClipDisplayItem),
208    ClipChain(ClipChainItem, Vec<ClipId>),
209
210    Iframe(IframeDisplayItem),
211    PushReferenceFrame(ReferenceFrameDisplayListItem),
212    PushStackingContext(PushStackingContextDisplayItem),
213
214    SetGradientStops(Vec<GradientStop>),
215    SetFilterOps(Vec<FilterOp>),
216    SetFilterData(FilterData),
217    SetPoints(Vec<LayoutPoint>),
218
219    PopReferenceFrame,
220    PopStackingContext,
221    PopAllShadows,
222
223    DebugMarker(u32)
224}
225
226#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
227pub struct ImageMaskClipDisplayItem {
228    pub id: ClipId,
229    pub spatial_id: SpatialId,
230    pub image_mask: ImageMask,
231    pub fill_rule: FillRule,
232} // IMPLICIT points: Vec<LayoutPoint>
233
234#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
235pub struct RectClipDisplayItem {
236    pub id: ClipId,
237    pub spatial_id: SpatialId,
238    pub clip_rect: LayoutRect,
239}
240
241#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
242pub struct RoundedRectClipDisplayItem {
243    pub id: ClipId,
244    pub spatial_id: SpatialId,
245    pub clip: ComplexClipRegion,
246}
247
248/// The minimum and maximum allowable offset for a sticky frame in a single dimension.
249#[repr(C)]
250#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
251pub struct StickyOffsetBounds {
252    /// The minimum offset for this frame, typically a negative value, which specifies how
253    /// far in the negative direction the sticky frame can offset its contents in this
254    /// dimension.
255    pub min: f32,
256
257    /// The maximum offset for this frame, typically a positive value, which specifies how
258    /// far in the positive direction the sticky frame can offset its contents in this
259    /// dimension.
260    pub max: f32,
261}
262
263impl StickyOffsetBounds {
264    pub fn new(min: f32, max: f32) -> StickyOffsetBounds {
265        StickyOffsetBounds { min, max }
266    }
267}
268
269#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
270pub struct StickyFrameDescriptor {
271    pub id: SpatialId,
272    pub parent_spatial_id: SpatialId,
273    pub bounds: LayoutRect,
274
275    /// The margins that should be maintained between the edge of the parent viewport and this
276    /// sticky frame. A margin of None indicates that the sticky frame should not stick at all
277    /// to that particular edge of the viewport.
278    pub margins: SideOffsets2D<Option<f32>, LayoutPixel>,
279
280    /// The minimum and maximum vertical offsets for this sticky frame. Ignoring these constraints,
281    /// the sticky frame will continue to stick to the edge of the viewport as its original
282    /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the
283    /// original position relative to non-sticky content within the same scrolling frame.
284    pub vertical_offset_bounds: StickyOffsetBounds,
285
286    /// The minimum and maximum horizontal offsets for this sticky frame. Ignoring these constraints,
287    /// the sticky frame will continue to stick to the edge of the viewport as its original
288    /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the
289    /// original position relative to non-sticky content within the same scrolling frame.
290    pub horizontal_offset_bounds: StickyOffsetBounds,
291
292    /// The amount of offset that has already been applied to the sticky frame. A positive y
293    /// component this field means that a top-sticky item was in a scrollframe that has been
294    /// scrolled down, such that the sticky item's position needed to be offset downwards by
295    /// `previously_applied_offset.y`. A negative y component corresponds to the upward offset
296    /// applied due to bottom-stickiness. The x-axis works analogously.
297    pub previously_applied_offset: LayoutVector2D,
298
299    /// A property binding that we use to store an animation ID for APZ
300    pub transform: Option<PropertyBinding<LayoutTransform>>,
301}
302
303#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
304pub struct ScrollFrameDescriptor {
305    /// The id of the space this scroll frame creates
306    pub scroll_frame_id: SpatialId,
307    /// The size of the contents this contains (so the backend knows how far it can scroll).
308    // FIXME: this can *probably* just be a size? Origin seems to just get thrown out.
309    pub content_rect: LayoutRect,
310    pub frame_rect: LayoutRect,
311    pub parent_space: SpatialId,
312    pub external_id: ExternalScrollId,
313    /// The amount this scrollframe has already been scrolled by, in the caller.
314    /// This means that all the display items that are inside the scrollframe
315    /// will have their coordinates shifted by this amount, and this offset
316    /// should be added to those display item coordinates in order to get a
317    /// normalized value that is consistent across display lists.
318    pub external_scroll_offset: LayoutVector2D,
319    /// The generation of the external_scroll_offset.
320    pub scroll_offset_generation: APZScrollGeneration,
321    /// Whether this scrollframe document has any scroll-linked effect or not.
322    pub has_scroll_linked_effect: HasScrollLinkedEffect,
323}
324
325/// A solid or an animating color to draw (may not actually be a rectangle due to complex clips)
326#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
327pub struct RectangleDisplayItem {
328    pub common: CommonItemProperties,
329    pub bounds: LayoutRect,
330    pub color: PropertyBinding<ColorF>,
331}
332
333/// A minimal hit-testable item for the parent browser's convenience, and is
334/// slimmer than a RectangleDisplayItem (no color). The existence of this as a
335/// distinct item also makes it easier to inspect/debug display items.
336#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
337pub struct HitTestDisplayItem {
338    pub rect: LayoutRect,
339    pub clip_chain_id: ClipChainId,
340    pub spatial_id: SpatialId,
341    pub flags: PrimitiveFlags,
342    pub tag: ItemTag,
343}
344
345#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
346pub struct LineDisplayItem {
347    pub common: CommonItemProperties,
348    /// We need a separate rect from common.clip_rect to encode cute
349    /// tricks that firefox does to make a series of text-decorations seamlessly
350    /// line up -- snapping the decorations to a multiple of their period, and
351    /// then clipping them to their "proper" area. This rect is that "logical"
352    /// snapped area that may be clipped to the right size by the clip_rect.
353    pub area: LayoutRect,
354    /// Whether the rect is interpretted as vertical or horizontal
355    pub orientation: LineOrientation,
356    /// This could potentially be implied from area, but we currently prefer
357    /// that this is the responsibility of the layout engine. Value irrelevant
358    /// for non-wavy lines.
359    // FIXME: this was done before we could use tagged unions in enums, but now
360    // it should just be part of LineStyle::Wavy.
361    pub wavy_line_thickness: f32,
362    pub color: ColorF,
363    pub style: LineStyle,
364}
365
366#[repr(u8)]
367#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
368pub enum LineOrientation {
369    Vertical,
370    Horizontal,
371}
372
373#[repr(u8)]
374#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
375pub enum LineStyle {
376    Solid,
377    Dotted,
378    Dashed,
379    Wavy,
380}
381
382#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
383pub struct TextDisplayItem {
384    pub common: CommonItemProperties,
385    /// The area all the glyphs should be found in. Strictly speaking this isn't
386    /// necessarily needed, but layout engines should already "know" this, and we
387    /// use it cull and size things quickly before glyph layout is done. Currently
388    /// the glyphs *can* be outside these bounds, but that should imply they
389    /// can be cut off.
390    // FIXME: these are currently sometimes ignored to keep some old wrench tests
391    // working, but we should really just fix the tests!
392    pub bounds: LayoutRect,
393    pub font_key: font::FontInstanceKey,
394    pub color: ColorF,
395    pub glyph_options: Option<font::GlyphOptions>,
396} // IMPLICIT: glyphs: Vec<font::GlyphInstance>
397
398#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
399pub struct NormalBorder {
400    pub left: BorderSide,
401    pub right: BorderSide,
402    pub top: BorderSide,
403    pub bottom: BorderSide,
404    pub radius: BorderRadius,
405    /// Whether to apply anti-aliasing on the border corners.
406    ///
407    /// Note that for this to be `false` and work, this requires the borders to
408    /// be solid, and no border-radius.
409    pub do_aa: bool,
410}
411
412impl NormalBorder {
413    fn can_disable_antialiasing(&self) -> bool {
414        fn is_valid(style: BorderStyle) -> bool {
415            style == BorderStyle::Solid || style == BorderStyle::None
416        }
417
418        self.radius.is_zero() &&
419            is_valid(self.top.style) &&
420            is_valid(self.left.style) &&
421            is_valid(self.bottom.style) &&
422            is_valid(self.right.style)
423    }
424
425    /// Normalizes a border so that we don't render disallowed stuff, like inset
426    /// borders that are less than two pixels wide.
427    #[inline]
428    pub fn normalize(&mut self, widths: &LayoutSideOffsets) {
429        debug_assert!(
430            self.do_aa || self.can_disable_antialiasing(),
431            "Unexpected disabled-antialiasing in a border, likely won't work or will be ignored"
432        );
433
434        #[inline]
435        fn renders_small_border_solid(style: BorderStyle) -> bool {
436            match style {
437                BorderStyle::Groove |
438                BorderStyle::Ridge => true,
439                _ => false,
440            }
441        }
442
443        let normalize_side = |side: &mut BorderSide, width: f32| {
444            if renders_small_border_solid(side.style) && width < 2. {
445                side.style = BorderStyle::Solid;
446            }
447        };
448
449        normalize_side(&mut self.left, widths.left);
450        normalize_side(&mut self.right, widths.right);
451        normalize_side(&mut self.top, widths.top);
452        normalize_side(&mut self.bottom, widths.bottom);
453    }
454}
455
456#[repr(u8)]
457#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)]
458pub enum RepeatMode {
459    Stretch,
460    Repeat,
461    Round,
462    Space,
463}
464
465#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
466pub enum NinePatchBorderSource {
467    Image(ImageKey, ImageRendering),
468    Gradient(Gradient),
469    RadialGradient(RadialGradient),
470    ConicGradient(ConicGradient),
471}
472
473#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
474pub struct NinePatchBorder {
475    /// Describes what to use as the 9-patch source image. If this is an image,
476    /// it will be stretched to fill the size given by width x height.
477    pub source: NinePatchBorderSource,
478
479    /// The width of the 9-part image.
480    pub width: i32,
481
482    /// The height of the 9-part image.
483    pub height: i32,
484
485    /// Distances from each edge where the image should be sliced up. These
486    /// values are in 9-part-image space (the same space as width and height),
487    /// and the resulting image parts will be used to fill the corresponding
488    /// parts of the border as given by the border widths. This can lead to
489    /// stretching.
490    /// Slices can be overlapping. In that case, the same pixels from the
491    /// 9-part image will show up in multiple parts of the resulting border.
492    pub slice: DeviceIntSideOffsets,
493
494    /// Controls whether the center of the 9 patch image is rendered or
495    /// ignored. The center is never rendered if the slices are overlapping.
496    pub fill: bool,
497
498    /// Determines what happens if the horizontal side parts of the 9-part
499    /// image have a different size than the horizontal parts of the border.
500    pub repeat_horizontal: RepeatMode,
501
502    /// Determines what happens if the vertical side parts of the 9-part
503    /// image have a different size than the vertical parts of the border.
504    pub repeat_vertical: RepeatMode,
505}
506
507#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
508pub enum BorderDetails {
509    Normal(NormalBorder),
510    NinePatch(NinePatchBorder),
511}
512
513#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
514pub struct BorderDisplayItem {
515    pub common: CommonItemProperties,
516    pub bounds: LayoutRect,
517    pub widths: LayoutSideOffsets,
518    pub details: BorderDetails,
519}
520
521#[repr(C)]
522#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
523pub enum BorderRadiusKind {
524    Uniform,
525    NonUniform,
526}
527
528#[repr(C)]
529#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
530pub struct BorderRadius {
531    pub top_left: LayoutSize,
532    pub top_right: LayoutSize,
533    pub bottom_left: LayoutSize,
534    pub bottom_right: LayoutSize,
535}
536
537impl Default for BorderRadius {
538    fn default() -> Self {
539        BorderRadius {
540            top_left: LayoutSize::zero(),
541            top_right: LayoutSize::zero(),
542            bottom_left: LayoutSize::zero(),
543            bottom_right: LayoutSize::zero(),
544        }
545    }
546}
547
548#[repr(C)]
549#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
550pub struct BorderSide {
551    pub color: ColorF,
552    pub style: BorderStyle,
553}
554
555#[repr(u32)]
556#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq, PeekPoke)]
557pub enum BorderStyle {
558    None = 0,
559    Solid = 1,
560    Double = 2,
561    Dotted = 3,
562    Dashed = 4,
563    Hidden = 5,
564    Groove = 6,
565    Ridge = 7,
566    Inset = 8,
567    Outset = 9,
568}
569
570impl BorderStyle {
571    pub fn is_hidden(self) -> bool {
572        self == BorderStyle::Hidden || self == BorderStyle::None
573    }
574}
575
576#[repr(u8)]
577#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
578pub enum BoxShadowClipMode {
579    Outset = 0,
580    Inset = 1,
581}
582
583#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
584pub struct BoxShadowDisplayItem {
585    pub common: CommonItemProperties,
586    pub box_bounds: LayoutRect,
587    pub offset: LayoutVector2D,
588    pub color: ColorF,
589    pub blur_radius: f32,
590    pub spread_radius: f32,
591    pub border_radius: BorderRadius,
592    pub shadow_radius: BorderRadius,
593    pub clip_mode: BoxShadowClipMode,
594}
595
596#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
597pub struct PushShadowDisplayItem {
598    pub space_and_clip: SpaceAndClipInfo,
599    pub shadow: Shadow,
600    pub should_inflate: bool,
601}
602
603#[repr(C)]
604#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
605pub struct Shadow {
606    pub offset: LayoutVector2D,
607    pub color: ColorF,
608    pub blur_radius: f32,
609}
610
611#[repr(u8)]
612#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)]
613pub enum ExtendMode {
614    Clamp,
615    Repeat,
616}
617
618#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
619pub struct Gradient {
620    pub start_point: LayoutPoint,
621    pub end_point: LayoutPoint,
622    pub extend_mode: ExtendMode,
623} // IMPLICIT: stops: Vec<GradientStop>
624
625impl Gradient {
626    pub fn is_valid(&self) -> bool {
627        self.start_point.x.is_finite() &&
628            self.start_point.y.is_finite() &&
629            self.end_point.x.is_finite() &&
630            self.end_point.y.is_finite()
631    }
632}
633
634/// The area
635#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
636pub struct GradientDisplayItem {
637    /// NOTE: common.clip_rect is the area the gradient covers
638    pub common: CommonItemProperties,
639    /// The area to tile the gradient over (first tile starts at origin of this rect)
640    // FIXME: this should ideally just be `tile_origin` here, with the clip_rect
641    // defining the bounds of the item. Needs non-trivial backend changes.
642    pub bounds: LayoutRect,
643    /// How big a tile of the of the gradient should be (common case: bounds.size)
644    pub tile_size: LayoutSize,
645    /// The space between tiles of the gradient (common case: 0)
646    pub tile_spacing: LayoutSize,
647    pub gradient: Gradient,
648}
649
650#[repr(C)]
651#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
652pub struct GradientStop {
653    pub offset: f32,
654    pub color: ColorF,
655}
656
657#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
658pub struct RadialGradient {
659    pub center: LayoutPoint,
660    pub radius: LayoutSize,
661    pub start_offset: f32,
662    pub end_offset: f32,
663    pub extend_mode: ExtendMode,
664} // IMPLICIT stops: Vec<GradientStop>
665
666impl RadialGradient {
667    pub fn is_valid(&self) -> bool {
668        self.center.x.is_finite() &&
669            self.center.y.is_finite() &&
670            self.start_offset.is_finite() &&
671            self.end_offset.is_finite()
672    }
673}
674
675#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
676pub struct ConicGradient {
677    pub center: LayoutPoint,
678    pub angle: f32,
679    pub start_offset: f32,
680    pub end_offset: f32,
681    pub extend_mode: ExtendMode,
682} // IMPLICIT stops: Vec<GradientStop>
683
684impl ConicGradient {
685    pub fn is_valid(&self) -> bool {
686        self.center.x.is_finite() &&
687            self.center.y.is_finite() &&
688            self.angle.is_finite() &&
689            self.start_offset.is_finite() &&
690            self.end_offset.is_finite()
691    }
692}
693
694/// Just an abstraction for bundling up a bunch of clips into a "super clip".
695#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
696pub struct ClipChainItem {
697    pub id: ClipChainId,
698    pub parent: Option<ClipChainId>,
699} // IMPLICIT clip_ids: Vec<ClipId>
700
701#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
702pub struct RadialGradientDisplayItem {
703    pub common: CommonItemProperties,
704    /// The area to tile the gradient over (first tile starts at origin of this rect)
705    // FIXME: this should ideally just be `tile_origin` here, with the clip_rect
706    // defining the bounds of the item. Needs non-trivial backend changes.
707    pub bounds: LayoutRect,
708    pub gradient: RadialGradient,
709    pub tile_size: LayoutSize,
710    pub tile_spacing: LayoutSize,
711}
712
713#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
714pub struct ConicGradientDisplayItem {
715    pub common: CommonItemProperties,
716    /// The area to tile the gradient over (first tile starts at origin of this rect)
717    // FIXME: this should ideally just be `tile_origin` here, with the clip_rect
718    // defining the bounds of the item. Needs non-trivial backend changes.
719    pub bounds: LayoutRect,
720    pub gradient: ConicGradient,
721    pub tile_size: LayoutSize,
722    pub tile_spacing: LayoutSize,
723}
724
725/// Renders a filtered region of its backdrop
726#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
727pub struct BackdropFilterDisplayItem {
728    pub common: CommonItemProperties,
729}
730// IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive>
731
732#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
733pub struct ReferenceFrameDisplayListItem {
734}
735
736#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
737pub struct ReferenceFrameDescriptor {
738    pub origin: LayoutPoint,
739    pub parent_spatial_id: SpatialId,
740    pub reference_frame: ReferenceFrame,
741}
742
743#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
744pub enum ReferenceFrameKind {
745    /// A normal transform matrix, may contain perspective (the CSS transform property)
746    Transform {
747        /// Optionally marks the transform as only ever having a simple 2D scale or translation,
748        /// allowing for optimizations.
749        is_2d_scale_translation: bool,
750        /// Marks that the transform should be snapped. Used for transforms which animate in
751        /// response to scrolling, eg for zooming or dynamic toolbar fixed-positioning.
752        should_snap: bool,
753        /// Marks the transform being a part of the CSS stacking context that also has
754        /// a perspective. In this case, backface visibility takes this perspective into
755        /// account.
756        paired_with_perspective: bool,
757    },
758    /// A perspective transform, that optionally scrolls relative to a specific scroll node
759    Perspective {
760        scrolling_relative_to: Option<ExternalScrollId>,
761    }
762}
763
764#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
765pub enum Rotation {
766    Degree0,
767    Degree90,
768    Degree180,
769    Degree270,
770}
771
772impl Rotation {
773    pub fn to_matrix(
774        &self,
775        size: LayoutSize,
776    ) -> LayoutTransform {
777        let (shift_center_to_origin, angle) = match self {
778            Rotation::Degree0 => {
779              (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.))
780            },
781            Rotation::Degree90 => {
782              (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.))
783            },
784            Rotation::Degree180 => {
785              (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.))
786            },
787            Rotation::Degree270 => {
788              (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.))
789            },
790        };
791        let shift_origin_to_center = LayoutTransform::translation(size.width / 2., size.height / 2., 0.);
792
793        shift_center_to_origin
794            .then(&LayoutTransform::rotation(0., 0., 1.0, angle))
795            .then(&shift_origin_to_center)
796    }
797}
798
799#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
800pub enum ReferenceTransformBinding {
801    /// Standard reference frame which contains a precomputed transform.
802    Static {
803        binding: PropertyBinding<LayoutTransform>,
804    },
805    /// Computed reference frame which dynamically calculates the transform
806    /// based on the given parameters. The reference is the content size of
807    /// the parent iframe, which is affected by snapping.
808    ///
809    /// This is used when a transform depends on the layout size of an
810    /// element, otherwise the difference between the unsnapped size
811    /// used in the transform, and the snapped size calculated during scene
812    /// building can cause seaming.
813    Computed {
814        scale_from: Option<LayoutSize>,
815        vertical_flip: bool,
816        rotation: Rotation,
817    },
818}
819
820impl Default for ReferenceTransformBinding {
821    fn default() -> Self {
822        ReferenceTransformBinding::Static {
823            binding: Default::default(),
824        }
825    }
826}
827
828#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
829pub struct ReferenceFrame {
830    pub kind: ReferenceFrameKind,
831    pub transform_style: TransformStyle,
832    /// The transform matrix, either the perspective matrix or the transform
833    /// matrix.
834    pub transform: ReferenceTransformBinding,
835    pub id: SpatialId,
836}
837
838/// If passed in a stacking context display item, inform WebRender that
839/// the contents of the stacking context should be retained into a texture
840/// and associated to an image key.
841///
842/// Image display items can then display the cached snapshot using the
843/// same image key.
844///
845/// The flow for creating/using/deleting snapshots is the same as with
846/// regular images:
847///  - The image key must have been created with `Transaction::add_snapshot_image`.
848///  - The current scene must not contain references to the snapshot when
849///    `Transaction::delete_snapshot_image` is called.
850#[repr(C)]
851#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
852pub struct SnapshotInfo {
853    /// The image key to associate the snapshot with.
854    pub key: SnapshotImageKey,
855    /// The bounds of the snapshot in local space.
856    ///
857    /// This rectangle is relative to the same coordinate space as the
858    /// child items of the stacking context.
859    pub area: LayoutRect,
860    /// If true, detach the stacking context from the scene and only
861    /// render it into the snapshot.
862    /// If false, the stacking context rendered in the frame normally
863    /// in addition to being cached into the snapshot.
864    pub detached: bool,
865}
866
867#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
868pub struct PushStackingContextDisplayItem {
869    pub spatial_id: SpatialId,
870    pub snapshot: Option<SnapshotInfo>,
871    pub prim_flags: PrimitiveFlags,
872    pub stacking_context: StackingContext,
873}
874
875#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
876pub struct StackingContext {
877    pub transform_style: TransformStyle,
878    pub mix_blend_mode: MixBlendMode,
879    pub clip_chain_id: Option<ClipChainId>,
880    pub raster_space: RasterSpace,
881    pub flags: StackingContextFlags,
882}
883// IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive>
884
885#[repr(u8)]
886#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
887pub enum TransformStyle {
888    Flat = 0,
889    Preserve3D = 1,
890}
891
892/// Configure whether the contents of a stacking context
893/// should be rasterized in local space or screen space.
894/// Local space rasterized pictures are typically used
895/// when we want to cache the output, and performance is
896/// important. Note that this is a performance hint only,
897/// which WR may choose to ignore.
898#[derive(Clone, Copy, Debug, Deserialize, PartialEq, MallocSizeOf, Serialize, PeekPoke)]
899#[repr(u8)]
900pub enum RasterSpace {
901    // Rasterize in local-space, applying supplied scale to primitives.
902    // Best performance, but lower quality.
903    Local(f32),
904
905    // Rasterize the picture in screen-space, including rotation / skew etc in
906    // the rasterized element. Best quality, but slower performance. Note that
907    // any stacking context with a perspective transform will be rasterized
908    // in local-space, even if this is set.
909    Screen,
910}
911
912impl RasterSpace {
913    pub fn local_scale(self) -> Option<f32> {
914        match self {
915            RasterSpace::Local(scale) => Some(scale),
916            RasterSpace::Screen => None,
917        }
918    }
919}
920
921impl Eq for RasterSpace {}
922
923impl Hash for RasterSpace {
924    fn hash<H: Hasher>(&self, state: &mut H) {
925        match self {
926            RasterSpace::Screen => {
927                0.hash(state);
928            }
929            RasterSpace::Local(scale) => {
930                // Note: this is inconsistent with the Eq impl for -0.0 (don't care).
931                1.hash(state);
932                scale.to_bits().hash(state);
933            }
934        }
935    }
936}
937
938#[repr(C)]
939#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)]
940pub struct StackingContextFlags(u8);
941
942bitflags! {
943    impl StackingContextFlags: u8 {
944        /// If true, this stacking context is a blend container than contains
945        /// mix-blend-mode children (and should thus be isolated).
946        const IS_BLEND_CONTAINER = 1 << 0;
947        /// If true, this stacking context is a wrapper around a backdrop-filter (e.g. for
948        /// a clip-mask). This is needed to allow the correct selection of a backdrop root
949        /// since a clip-mask stacking context creates a parent surface.
950        const WRAPS_BACKDROP_FILTER = 1 << 1;
951        /// If true, this stacking context must be isolated from parent by a surface.
952        const FORCED_ISOLATION = 1 << 2;
953    }
954}
955
956impl core::fmt::Debug for StackingContextFlags {
957    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
958        if self.is_empty() {
959            write!(f, "{:#x}", Self::empty().bits())
960        } else {
961            bitflags::parser::to_writer(self, f)
962        }
963    }
964}
965
966impl Default for StackingContextFlags {
967    fn default() -> Self {
968        StackingContextFlags::empty()
969    }
970}
971
972#[repr(u8)]
973#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
974pub enum MixBlendMode {
975    Normal = 0,
976    Multiply = 1,
977    Screen = 2,
978    Overlay = 3,
979    Darken = 4,
980    Lighten = 5,
981    ColorDodge = 6,
982    ColorBurn = 7,
983    HardLight = 8,
984    SoftLight = 9,
985    Difference = 10,
986    Exclusion = 11,
987    Hue = 12,
988    Saturation = 13,
989    Color = 14,
990    Luminosity = 15,
991    PlusLighter = 16,
992}
993
994#[repr(C)]
995#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
996pub enum ColorSpace {
997    Srgb,
998    LinearRgb,
999}
1000
1001/// Available composite operoations for the composite filter primitive
1002#[repr(C)]
1003#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1004pub enum CompositeOperator {
1005    Over,
1006    In,
1007    Atop,
1008    Out,
1009    Xor,
1010    Lighter,
1011    Arithmetic([f32; 4]),
1012}
1013
1014impl CompositeOperator {
1015    // This must stay in sync with the composite operator defines in cs_svg_filter.glsl
1016    pub fn as_int(&self) -> u32 {
1017        match self {
1018            CompositeOperator::Over => 0,
1019            CompositeOperator::In => 1,
1020            CompositeOperator::Out => 2,
1021            CompositeOperator::Atop => 3,
1022            CompositeOperator::Xor => 4,
1023            CompositeOperator::Lighter => 5,
1024            CompositeOperator::Arithmetic(..) => 6,
1025        }
1026    }
1027}
1028
1029/// An input to a SVG filter primitive.
1030#[repr(C)]
1031#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1032pub enum FilterPrimitiveInput {
1033    /// The input is the original graphic that the filter is being applied to.
1034    Original,
1035    /// The input is the output of the previous filter primitive in the filter primitive chain.
1036    Previous,
1037    /// The input is the output of the filter primitive at the given index in the filter primitive chain.
1038    OutputOfPrimitiveIndex(usize),
1039}
1040
1041impl FilterPrimitiveInput {
1042    /// Gets the index of the input.
1043    /// Returns `None` if the source graphic is the input.
1044    pub fn to_index(self, cur_index: usize) -> Option<usize> {
1045        match self {
1046            FilterPrimitiveInput::Previous if cur_index > 0 => Some(cur_index - 1),
1047            FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => Some(index),
1048            _ => None,
1049        }
1050    }
1051}
1052
1053#[repr(C)]
1054#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1055pub struct BlendPrimitive {
1056    pub input1: FilterPrimitiveInput,
1057    pub input2: FilterPrimitiveInput,
1058    pub mode: MixBlendMode,
1059}
1060
1061#[repr(C)]
1062#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1063pub struct FloodPrimitive {
1064    pub color: ColorF,
1065}
1066
1067impl FloodPrimitive {
1068    pub fn sanitize(&mut self) {
1069        self.color.r = self.color.r.clamp(0.0, 1.0);
1070        self.color.g = self.color.g.clamp(0.0, 1.0);
1071        self.color.b = self.color.b.clamp(0.0, 1.0);
1072        self.color.a = self.color.a.clamp(0.0, 1.0);
1073    }
1074}
1075
1076#[repr(C)]
1077#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1078pub struct BlurPrimitive {
1079    pub input: FilterPrimitiveInput,
1080    pub width: f32,
1081    pub height: f32,
1082}
1083
1084#[repr(C)]
1085#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1086pub struct OpacityPrimitive {
1087    pub input: FilterPrimitiveInput,
1088    pub opacity: f32,
1089}
1090
1091impl OpacityPrimitive {
1092    pub fn sanitize(&mut self) {
1093        self.opacity = self.opacity.clamp(0.0, 1.0);
1094    }
1095}
1096
1097/// cbindgen:derive-eq=false
1098#[repr(C)]
1099#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1100pub struct ColorMatrixPrimitive {
1101    pub input: FilterPrimitiveInput,
1102    pub matrix: [f32; 20],
1103}
1104
1105#[repr(C)]
1106#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1107pub struct DropShadowPrimitive {
1108    pub input: FilterPrimitiveInput,
1109    pub shadow: Shadow,
1110}
1111
1112#[repr(C)]
1113#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1114pub struct ComponentTransferPrimitive {
1115    pub input: FilterPrimitiveInput,
1116    // Component transfer data is stored in FilterData.
1117}
1118
1119#[repr(C)]
1120#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1121pub struct IdentityPrimitive {
1122    pub input: FilterPrimitiveInput,
1123}
1124
1125#[repr(C)]
1126#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1127pub struct OffsetPrimitive {
1128    pub input: FilterPrimitiveInput,
1129    pub offset: LayoutVector2D,
1130}
1131
1132#[repr(C)]
1133#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1134pub struct CompositePrimitive {
1135    pub input1: FilterPrimitiveInput,
1136    pub input2: FilterPrimitiveInput,
1137    pub operator: CompositeOperator,
1138}
1139
1140/// See: https://github.com/eqrion/cbindgen/issues/9
1141/// cbindgen:derive-eq=false
1142#[repr(C)]
1143#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
1144pub enum FilterPrimitiveKind {
1145    Identity(IdentityPrimitive),
1146    Blend(BlendPrimitive),
1147    Flood(FloodPrimitive),
1148    Blur(BlurPrimitive),
1149    // TODO: Support animated opacity?
1150    Opacity(OpacityPrimitive),
1151    /// cbindgen:derive-eq=false
1152    ColorMatrix(ColorMatrixPrimitive),
1153    DropShadow(DropShadowPrimitive),
1154    ComponentTransfer(ComponentTransferPrimitive),
1155    Offset(OffsetPrimitive),
1156    Composite(CompositePrimitive),
1157}
1158
1159impl Default for FilterPrimitiveKind {
1160    fn default() -> Self {
1161        FilterPrimitiveKind::Identity(IdentityPrimitive::default())
1162    }
1163}
1164
1165impl FilterPrimitiveKind {
1166    pub fn sanitize(&mut self) {
1167        match self {
1168            FilterPrimitiveKind::Flood(flood) => flood.sanitize(),
1169            FilterPrimitiveKind::Opacity(opacity) => opacity.sanitize(),
1170
1171            // No sanitization needed.
1172            FilterPrimitiveKind::Identity(..) |
1173            FilterPrimitiveKind::Blend(..) |
1174            FilterPrimitiveKind::ColorMatrix(..) |
1175            FilterPrimitiveKind::Offset(..) |
1176            FilterPrimitiveKind::Composite(..) |
1177            FilterPrimitiveKind::Blur(..) |
1178            FilterPrimitiveKind::DropShadow(..) |
1179            // Component transfer's filter data is sanitized separately.
1180            FilterPrimitiveKind::ComponentTransfer(..) => {}
1181        }
1182    }
1183}
1184
1185/// SVG Filter Primitive.
1186/// See: https://github.com/eqrion/cbindgen/issues/9
1187/// cbindgen:derive-eq=false
1188#[repr(C)]
1189#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1190pub struct FilterPrimitive {
1191    pub kind: FilterPrimitiveKind,
1192    pub color_space: ColorSpace,
1193}
1194
1195impl FilterPrimitive {
1196    pub fn sanitize(&mut self) {
1197        self.kind.sanitize();
1198    }
1199}
1200
1201#[repr(C)]
1202#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, PeekPoke)]
1203pub enum FilterOpGraphPictureBufferId {
1204    #[default]
1205    /// empty slot in feMerge inputs
1206    None,
1207    /// reference to another (earlier) node in filter graph
1208    BufferId(i16),
1209}
1210
1211#[repr(C)]
1212#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PeekPoke)]
1213pub struct FilterOpGraphPictureReference {
1214    /// Id of the picture in question in a namespace unique to this filter DAG
1215    pub buffer_id: FilterOpGraphPictureBufferId,
1216}
1217
1218#[repr(C)]
1219#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PeekPoke)]
1220pub struct FilterOpGraphNode {
1221    /// True if color_interpolation_filter == LinearRgb; shader will convert
1222    /// sRGB texture pixel colors on load and convert back on store, for correct
1223    /// interpolation
1224    pub linear: bool,
1225    /// virtualized picture input binding 1 (i.e. texture source), typically
1226    /// this is used, but certain filters do not use it
1227    pub input: FilterOpGraphPictureReference,
1228    /// virtualized picture input binding 2 (i.e. texture sources), only certain
1229    /// filters use this
1230    pub input2: FilterOpGraphPictureReference,
1231    /// rect this node will render into, in filter space
1232    pub subregion: LayoutRect,
1233}
1234
1235/// Maximum number of SVGFE filters in one graph, this is constant size to avoid
1236/// allocating anything, and the SVG spec allows us to drop all filters on an
1237/// item if the graph is excessively complex - a graph this large will never be
1238/// a good user experience, performance-wise.
1239pub const SVGFE_GRAPH_MAX: usize = 256;
1240
1241#[repr(C)]
1242#[derive(Clone, Copy, Debug, Deserialize, Serialize, PeekPoke)]
1243pub enum FilterOp {
1244    /// Filter that does no transformation of the colors, needed for
1245    /// debug purposes, and is the default value in impl_default_for_enums.
1246    /// parameters: none
1247    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1248    Identity,
1249    /// apply blur effect
1250    /// parameters: stdDeviationX, stdDeviationY
1251    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1252    Blur(f32, f32),
1253    /// apply brightness effect
1254    /// parameters: amount
1255    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1256    Brightness(f32),
1257    /// apply contrast effect
1258    /// parameters: amount
1259    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1260    Contrast(f32),
1261    /// fade image toward greyscale version of image
1262    /// parameters: amount
1263    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1264    Grayscale(f32),
1265    /// fade image toward hue-rotated version of image (rotate RGB around color wheel)
1266    /// parameters: angle
1267    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1268    HueRotate(f32),
1269    /// fade image toward inverted image (1 - RGB)
1270    /// parameters: amount
1271    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1272    Invert(f32),
1273    /// multiplies color and alpha by opacity
1274    /// parameters: amount
1275    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1276    Opacity(PropertyBinding<f32>, f32),
1277    /// multiply saturation of colors
1278    /// parameters: amount
1279    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1280    Saturate(f32),
1281    /// fade image toward sepia tone version of image
1282    /// parameters: amount
1283    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1284    Sepia(f32),
1285    /// add drop shadow version of image to the image
1286    /// parameters: shadow
1287    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1288    DropShadow(Shadow),
1289    /// transform color and alpha in image through 4x5 color matrix (transposed for efficiency)
1290    /// parameters: matrix[5][4]
1291    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1292    ColorMatrix([f32; 20]),
1293    /// internal use - convert sRGB input to linear output
1294    /// parameters: none
1295    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1296    SrgbToLinear,
1297    /// internal use - convert linear input to sRGB output
1298    /// parameters: none
1299    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1300    LinearToSrgb,
1301    /// remap RGBA with color gradients and component swizzle
1302    /// parameters: FilterData
1303    /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear)
1304    ComponentTransfer,
1305    /// replace image with a solid color
1306    /// NOTE: UNUSED; Gecko never produces this filter
1307    /// parameters: color
1308    /// CSS filter semantics - operates on previous picture,uses sRGB space (non-linear)
1309    Flood(ColorF),
1310    /// Filter that copies the SourceGraphic image into the specified subregion,
1311    /// This is intentionally the only way to get SourceGraphic into the graph,
1312    /// as the filter region must be applied before it is used.
1313    /// parameters: FilterOpGraphNode
1314    /// SVG filter semantics - no inputs, no linear
1315    SVGFESourceGraphic{node: FilterOpGraphNode},
1316    /// Filter that copies the SourceAlpha image into the specified subregion,
1317    /// This is intentionally the only way to get SourceGraphic into the graph,
1318    /// as the filter region must be applied before it is used.
1319    /// parameters: FilterOpGraphNode
1320    /// SVG filter semantics - no inputs, no linear
1321    SVGFESourceAlpha{node: FilterOpGraphNode},
1322    /// Filter that does no transformation of the colors, used for subregion
1323    /// cropping only.
1324    SVGFEIdentity{node: FilterOpGraphNode},
1325    /// represents CSS opacity property as a graph node like the rest of the SVGFE* filters
1326    /// parameters: FilterOpGraphNode
1327    /// SVG filter semantics - selectable input(s), selectable between linear
1328    /// (default) and sRGB color space for calculations
1329    SVGFEOpacity{node: FilterOpGraphNode, valuebinding: PropertyBinding<f32>, value: f32},
1330    /// convert a color image to an alpha channel - internal use; generated by
1331    /// SVGFilterInstance::GetOrCreateSourceAlphaIndex().
1332    SVGFEToAlpha{node: FilterOpGraphNode},
1333    /// combine 2 images with SVG_FEBLEND_MODE_DARKEN
1334    /// parameters: FilterOpGraphNode
1335    /// SVG filter semantics - selectable input(s), selectable between linear
1336    /// (default) and sRGB color space for calculations
1337    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
1338    SVGFEBlendDarken{node: FilterOpGraphNode},
1339    /// combine 2 images with SVG_FEBLEND_MODE_LIGHTEN
1340    /// parameters: FilterOpGraphNode
1341    /// SVG filter semantics - selectable input(s), selectable between linear
1342    /// (default) and sRGB color space for calculations
1343    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
1344    SVGFEBlendLighten{node: FilterOpGraphNode},
1345    /// combine 2 images with SVG_FEBLEND_MODE_MULTIPLY
1346    /// parameters: FilterOpGraphNode
1347    /// SVG filter semantics - selectable input(s), selectable between linear
1348    /// (default) and sRGB color space for calculations
1349    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
1350    SVGFEBlendMultiply{node: FilterOpGraphNode},
1351    /// combine 2 images with SVG_FEBLEND_MODE_NORMAL
1352    /// parameters: FilterOpGraphNode
1353    /// SVG filter semantics - selectable input(s), selectable between linear
1354    /// (default) and sRGB color space for calculations
1355    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
1356    SVGFEBlendNormal{node: FilterOpGraphNode},
1357    /// combine 2 images with SVG_FEBLEND_MODE_SCREEN
1358    /// parameters: FilterOpGraphNode
1359    /// SVG filter semantics - selectable input(s), selectable between linear
1360    /// (default) and sRGB color space for calculations
1361    /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement
1362    SVGFEBlendScreen{node: FilterOpGraphNode},
1363    /// combine 2 images with SVG_FEBLEND_MODE_OVERLAY
1364    /// parameters: FilterOpGraphNode
1365    /// SVG filter semantics - selectable input(s), selectable between linear
1366    /// (default) and sRGB color space for calculations
1367    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1368    SVGFEBlendOverlay{node: FilterOpGraphNode},
1369    /// combine 2 images with SVG_FEBLEND_MODE_COLOR_DODGE
1370    /// parameters: FilterOpGraphNode
1371    /// SVG filter semantics - selectable input(s), selectable between linear
1372    /// (default) and sRGB color space for calculations
1373    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1374    SVGFEBlendColorDodge{node: FilterOpGraphNode},
1375    /// combine 2 images with SVG_FEBLEND_MODE_COLOR_BURN
1376    /// parameters: FilterOpGraphNode
1377    /// SVG filter semantics - selectable input(s), selectable between linear
1378    /// (default) and sRGB color space for calculations
1379    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1380    SVGFEBlendColorBurn{node: FilterOpGraphNode},
1381    /// combine 2 images with SVG_FEBLEND_MODE_HARD_LIGHT
1382    /// parameters: FilterOpGraphNode
1383    /// SVG filter semantics - selectable input(s), selectable between linear
1384    /// (default) and sRGB color space for calculations
1385    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1386    SVGFEBlendHardLight{node: FilterOpGraphNode},
1387    /// combine 2 images with SVG_FEBLEND_MODE_SOFT_LIGHT
1388    /// parameters: FilterOpGraphNode
1389    /// SVG filter semantics - selectable input(s), selectable between linear
1390    /// (default) and sRGB color space for calculations
1391    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1392    SVGFEBlendSoftLight{node: FilterOpGraphNode},
1393    /// combine 2 images with SVG_FEBLEND_MODE_DIFFERENCE
1394    /// parameters: FilterOpGraphNode
1395    /// SVG filter semantics - selectable input(s), selectable between linear
1396    /// (default) and sRGB color space for calculations
1397    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1398    SVGFEBlendDifference{node: FilterOpGraphNode},
1399    /// combine 2 images with SVG_FEBLEND_MODE_EXCLUSION
1400    /// parameters: FilterOpGraphNode
1401    /// SVG filter semantics - selectable input(s), selectable between linear
1402    /// (default) and sRGB color space for calculations
1403    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1404    SVGFEBlendExclusion{node: FilterOpGraphNode},
1405    /// combine 2 images with SVG_FEBLEND_MODE_HUE
1406    /// parameters: FilterOpGraphNode
1407    /// SVG filter semantics - selectable input(s), selectable between linear
1408    /// (default) and sRGB color space for calculations
1409    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1410    SVGFEBlendHue{node: FilterOpGraphNode},
1411    /// combine 2 images with SVG_FEBLEND_MODE_SATURATION
1412    /// parameters: FilterOpGraphNode
1413    /// SVG filter semantics - selectable input(s), selectable between linear
1414    /// (default) and sRGB color space for calculations
1415    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1416    SVGFEBlendSaturation{node: FilterOpGraphNode},
1417    /// combine 2 images with SVG_FEBLEND_MODE_COLOR
1418    /// parameters: FilterOpGraphNode
1419    /// SVG filter semantics - selectable input(s), selectable between linear
1420    /// (default) and sRGB color space for calculations
1421    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1422    SVGFEBlendColor{node: FilterOpGraphNode},
1423    /// combine 2 images with SVG_FEBLEND_MODE_LUMINOSITY
1424    /// parameters: FilterOpGraphNode
1425    /// SVG filter semantics - selectable input(s), selectable between linear
1426    /// (default) and sRGB color space for calculations
1427    /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
1428    SVGFEBlendLuminosity{node: FilterOpGraphNode},
1429    /// transform colors of image through 5x4 color matrix (transposed for efficiency)
1430    /// parameters: FilterOpGraphNode, matrix[5][4]
1431    /// SVG filter semantics - selectable input(s), selectable between linear
1432    /// (default) and sRGB color space for calculations
1433    /// Spec: https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement
1434    SVGFEColorMatrix{node: FilterOpGraphNode, values: [f32; 20]},
1435    /// transform colors of image through configurable gradients with component swizzle
1436    /// parameters: FilterOpGraphNode, FilterData
1437    /// SVG filter semantics - selectable input(s), selectable between linear
1438    /// (default) and sRGB color space for calculations
1439    /// Spec: https://www.w3.org/TR/filter-effects-1/#feComponentTransferElement
1440    SVGFEComponentTransfer{node: FilterOpGraphNode},
1441    /// composite 2 images with chosen composite mode with parameters for that mode
1442    /// parameters: FilterOpGraphNode, k1, k2, k3, k4
1443    /// SVG filter semantics - selectable input(s), selectable between linear
1444    /// (default) and sRGB color space for calculations
1445    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
1446    SVGFECompositeArithmetic{node: FilterOpGraphNode, k1: f32, k2: f32, k3: f32,
1447        k4: f32},
1448    /// composite 2 images with chosen composite mode with parameters for that mode
1449    /// parameters: FilterOpGraphNode
1450    /// SVG filter semantics - selectable input(s), selectable between linear
1451    /// (default) and sRGB color space for calculations
1452    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
1453    SVGFECompositeATop{node: FilterOpGraphNode},
1454    /// composite 2 images with chosen composite mode with parameters for that mode
1455    /// parameters: FilterOpGraphNode
1456    /// SVG filter semantics - selectable input(s), selectable between linear
1457    /// (default) and sRGB color space for calculations
1458    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
1459    SVGFECompositeIn{node: FilterOpGraphNode},
1460    /// composite 2 images with chosen composite mode with parameters for that mode
1461    /// parameters: FilterOpGraphNode
1462    /// SVG filter semantics - selectable input(s), selectable between linear
1463    /// (default) and sRGB color space for calculations
1464    /// Docs: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite
1465    SVGFECompositeLighter{node: FilterOpGraphNode},
1466    /// composite 2 images with chosen composite mode with parameters for that mode
1467    /// parameters: FilterOpGraphNode
1468    /// SVG filter semantics - selectable input(s), selectable between linear
1469    /// (default) and sRGB color space for calculations
1470    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
1471    SVGFECompositeOut{node: FilterOpGraphNode},
1472    /// composite 2 images with chosen composite mode with parameters for that mode
1473    /// parameters: FilterOpGraphNode
1474    /// SVG filter semantics - selectable input(s), selectable between linear
1475    /// (default) and sRGB color space for calculations
1476    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
1477    SVGFECompositeOver{node: FilterOpGraphNode},
1478    /// composite 2 images with chosen composite mode with parameters for that mode
1479    /// parameters: FilterOpGraphNode
1480    /// SVG filter semantics - selectable input(s), selectable between linear
1481    /// (default) and sRGB color space for calculations
1482    /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement
1483    SVGFECompositeXOR{node: FilterOpGraphNode},
1484    /// transform image through convolution matrix of up to 25 values (spec
1485    /// allows more but for performance reasons we do not)
1486    /// parameters: FilterOpGraphNode, orderX, orderY, kernelValues[25],
1487    ///  divisor, bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
1488    ///  preserveAlpha
1489    /// SVG filter semantics - selectable input(s), selectable between linear
1490    /// (default) and sRGB color space for calculations
1491    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
1492    SVGFEConvolveMatrixEdgeModeDuplicate{node: FilterOpGraphNode, order_x: i32,
1493        order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32,
1494        target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32,
1495        preserve_alpha: i32},
1496    /// transform image through convolution matrix of up to 25 values (spec
1497    /// allows more but for performance reasons we do not)
1498    /// parameters: FilterOpGraphNode, orderX, orderY, kernelValues[25],
1499    ///  divisor, bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
1500    ///  preserveAlpha
1501    /// SVG filter semantics - selectable input(s), selectable between linear
1502    /// (default) and sRGB color space for calculations
1503    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
1504    SVGFEConvolveMatrixEdgeModeNone{node: FilterOpGraphNode, order_x: i32,
1505        order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32,
1506        target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32,
1507        preserve_alpha: i32},
1508    /// transform image through convolution matrix of up to 25 values (spec
1509    /// allows more but for performance reasons we do not)
1510    /// parameters: FilterOpGraphNode, orderX, orderY, kernelValues[25],
1511    ///  divisor, bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY,
1512    /// preserveAlpha
1513    /// SVG filter semantics - selectable input(s), selectable between linear
1514    /// (default) and sRGB color space for calculations
1515    /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement
1516    SVGFEConvolveMatrixEdgeModeWrap{node: FilterOpGraphNode, order_x: i32,
1517        order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32,
1518        target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32,
1519        preserve_alpha: i32},
1520    /// calculate lighting based on heightmap image with provided values for a
1521    /// distant light source with specified direction
1522    /// parameters: FilterOpGraphNode, surfaceScale, diffuseConstant,
1523    ///  kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation
1524    /// SVG filter semantics - selectable input(s), selectable between linear
1525    /// (default) and sRGB color space for calculations
1526    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
1527    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement
1528    SVGFEDiffuseLightingDistant{node: FilterOpGraphNode, surface_scale: f32,
1529        diffuse_constant: f32, kernel_unit_length_x: f32,
1530        kernel_unit_length_y: f32, azimuth: f32, elevation: f32},
1531    /// calculate lighting based on heightmap image with provided values for a
1532    /// point light source at specified location
1533    /// parameters: FilterOpGraphNode, surfaceScale, diffuseConstant,
1534    ///  kernelUnitLengthX, kernelUnitLengthY, x, y, z
1535    /// SVG filter semantics - selectable input(s), selectable between linear
1536    /// (default) and sRGB color space for calculations
1537    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
1538    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement
1539    SVGFEDiffuseLightingPoint{node: FilterOpGraphNode, surface_scale: f32,
1540        diffuse_constant: f32, kernel_unit_length_x: f32,
1541        kernel_unit_length_y: f32, x: f32, y: f32, z: f32},
1542    /// calculate lighting based on heightmap image with provided values for a
1543    /// spot light source at specified location pointing at specified target
1544    /// location with specified hotspot sharpness and cone angle
1545    /// parameters: FilterOpGraphNode, surfaceScale, diffuseConstant,
1546    ///  kernelUnitLengthX, kernelUnitLengthY, x, y, z, pointsAtX, pointsAtY,
1547    ///  pointsAtZ, specularExponent, limitingConeAngle
1548    /// SVG filter semantics - selectable input(s), selectable between linear
1549    /// (default) and sRGB color space for calculations
1550    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement
1551    /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement
1552    SVGFEDiffuseLightingSpot{node: FilterOpGraphNode, surface_scale: f32,
1553        diffuse_constant: f32, kernel_unit_length_x: f32,
1554        kernel_unit_length_y: f32, x: f32, y: f32, z: f32, points_at_x: f32,
1555        points_at_y: f32, points_at_z: f32, cone_exponent: f32,
1556        limiting_cone_angle: f32},
1557    /// calculate a distorted version of first input image using offset values
1558    /// from second input image at specified intensity
1559    /// parameters: FilterOpGraphNode, scale, xChannelSelector, yChannelSelector
1560    /// SVG filter semantics - selectable input(s), selectable between linear
1561    /// (default) and sRGB color space for calculations
1562    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDisplacementMapElement
1563    SVGFEDisplacementMap{node: FilterOpGraphNode, scale: f32,
1564        x_channel_selector: u32, y_channel_selector: u32},
1565    /// create and merge a dropshadow version of the specified image's alpha
1566    /// channel with specified offset and blur radius
1567    /// parameters: FilterOpGraphNode, flood_color, flood_opacity, dx, dy,
1568    ///  stdDeviationX, stdDeviationY
1569    /// SVG filter semantics - selectable input(s), selectable between linear
1570    /// (default) and sRGB color space for calculations
1571    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDropShadowElement
1572    SVGFEDropShadow{node: FilterOpGraphNode, color: ColorF, dx: f32, dy: f32,
1573        std_deviation_x: f32, std_deviation_y: f32},
1574    /// synthesize a new image of specified size containing a solid color
1575    /// parameters: FilterOpGraphNode, color
1576    /// SVG filter semantics - selectable input(s), selectable between linear
1577    /// (default) and sRGB color space for calculations
1578    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEFloodElement
1579    SVGFEFlood{node: FilterOpGraphNode, color: ColorF},
1580    /// create a blurred version of the input image
1581    /// parameters: FilterOpGraphNode, stdDeviationX, stdDeviationY
1582    /// SVG filter semantics - selectable input(s), selectable between linear
1583    /// (default) and sRGB color space for calculations
1584    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEGaussianBlurElement
1585    SVGFEGaussianBlur{node: FilterOpGraphNode, std_deviation_x: f32, std_deviation_y: f32},
1586    /// synthesize a new image based on a url (i.e. blob image source)
1587    /// parameters: FilterOpGraphNode, sampling_filter (see SamplingFilter in Types.h), transform
1588    /// SVG filter semantics - selectable input(s), selectable between linear
1589    /// (default) and sRGB color space for calculations
1590    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEImageElement
1591    SVGFEImage{node: FilterOpGraphNode, sampling_filter: u32, matrix: [f32; 6]},
1592    /// create a new image based on the input image with the contour stretched
1593    /// outward (dilate operator)
1594    /// parameters: FilterOpGraphNode, radiusX, radiusY
1595    /// SVG filter semantics - selectable input(s), selectable between linear
1596    /// (default) and sRGB color space for calculations
1597    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
1598    SVGFEMorphologyDilate{node: FilterOpGraphNode, radius_x: f32, radius_y: f32},
1599    /// create a new image based on the input image with the contour shrunken
1600    /// inward (erode operator)
1601    /// parameters: FilterOpGraphNode, radiusX, radiusY
1602    /// SVG filter semantics - selectable input(s), selectable between linear
1603    /// (default) and sRGB color space for calculations
1604    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement
1605    SVGFEMorphologyErode{node: FilterOpGraphNode, radius_x: f32, radius_y: f32},
1606    /// create a new image that is a scrolled version of the input image, this
1607    /// is basically a no-op as we support offset in the graph node
1608    /// parameters: FilterOpGraphNode
1609    /// SVG filter semantics - selectable input(s), selectable between linear
1610    /// (default) and sRGB color space for calculations
1611    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEOffsetElement
1612    SVGFEOffset{node: FilterOpGraphNode, offset_x: f32, offset_y: f32},
1613    /// calculate lighting based on heightmap image with provided values for a
1614    /// distant light source with specified direction
1615    /// parameters: FilerData, surfaceScale, specularConstant, specularExponent,
1616    ///  kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation
1617    /// SVG filter semantics - selectable input(s), selectable between linear
1618    /// (default) and sRGB color space for calculations
1619    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
1620    /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement
1621    SVGFESpecularLightingDistant{node: FilterOpGraphNode, surface_scale: f32,
1622        specular_constant: f32, specular_exponent: f32,
1623        kernel_unit_length_x: f32, kernel_unit_length_y: f32, azimuth: f32,
1624        elevation: f32},
1625    /// calculate lighting based on heightmap image with provided values for a
1626    /// point light source at specified location
1627    /// parameters: FilterOpGraphNode, surfaceScale, specularConstant,
1628    ///  specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z
1629    /// SVG filter semantics - selectable input(s), selectable between linear
1630    /// (default) and sRGB color space for calculations
1631    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
1632    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement
1633    SVGFESpecularLightingPoint{node: FilterOpGraphNode, surface_scale: f32,
1634        specular_constant: f32, specular_exponent: f32,
1635        kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
1636        z: f32},
1637    /// calculate lighting based on heightmap image with provided values for a
1638    /// spot light source at specified location pointing at specified target
1639    /// location with specified hotspot sharpness and cone angle
1640    /// parameters: FilterOpGraphNode, surfaceScale, specularConstant,
1641    ///  specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z,
1642    ///  pointsAtX, pointsAtY, pointsAtZ, specularExponent, limitingConeAngle
1643    /// SVG filter semantics - selectable input(s), selectable between linear
1644    /// (default) and sRGB color space for calculations
1645    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement
1646    ///  https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement
1647    SVGFESpecularLightingSpot{node: FilterOpGraphNode, surface_scale: f32,
1648        specular_constant: f32, specular_exponent: f32,
1649        kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
1650        z: f32, points_at_x: f32, points_at_y: f32, points_at_z: f32,
1651        cone_exponent: f32, limiting_cone_angle: f32},
1652    /// create a new image based on the input image, repeated throughout the
1653    /// output rectangle
1654    /// parameters: FilterOpGraphNode
1655    /// SVG filter semantics - selectable input(s), selectable between linear
1656    /// (default) and sRGB color space for calculations
1657    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETileElement
1658    SVGFETile{node: FilterOpGraphNode},
1659    /// synthesize a new image based on Fractal Noise (Perlin) with the chosen
1660    /// stitching mode
1661    /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY,
1662    ///  numOctaves, seed
1663    /// SVG filter semantics - selectable input(s), selectable between linear
1664    /// (default) and sRGB color space for calculations
1665    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
1666    SVGFETurbulenceWithFractalNoiseWithNoStitching{node: FilterOpGraphNode,
1667        base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32,
1668        seed: u32},
1669    /// synthesize a new image based on Fractal Noise (Perlin) with the chosen
1670    /// stitching mode
1671    /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY,
1672    ///  numOctaves, seed
1673    /// SVG filter semantics - selectable input(s), selectable between linear
1674    /// (default) and sRGB color space for calculations
1675    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
1676    SVGFETurbulenceWithFractalNoiseWithStitching{node: FilterOpGraphNode,
1677        base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32,
1678        seed: u32},
1679    /// synthesize a new image based on Turbulence Noise (offset vectors)
1680    /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY,
1681    ///  numOctaves, seed
1682    /// SVG filter semantics - selectable input(s), selectable between linear
1683    /// (default) and sRGB color space for calculations
1684    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
1685    SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{node: FilterOpGraphNode,
1686        base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32,
1687        seed: u32},
1688    /// synthesize a new image based on Turbulence Noise (offset vectors)
1689    /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY,
1690    ///  numOctaves, seed
1691    /// SVG filter semantics - selectable input(s), selectable between linear
1692    /// (default) and sRGB color space for calculations
1693    /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement
1694    SVGFETurbulenceWithTurbulenceNoiseWithStitching{node: FilterOpGraphNode,
1695        base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32, seed: u32},
1696}
1697
1698#[repr(u8)]
1699#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)]
1700pub enum ComponentTransferFuncType {
1701  Identity = 0,
1702  Table = 1,
1703  Discrete = 2,
1704  Linear = 3,
1705  Gamma = 4,
1706}
1707
1708#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
1709pub struct FilterData {
1710    /// ComponentTransfer / SVGFEComponentTransfer
1711    pub func_r_type: ComponentTransferFuncType,
1712    pub r_values: Vec<f32>,
1713    pub func_g_type: ComponentTransferFuncType,
1714    pub g_values: Vec<f32>,
1715    pub func_b_type: ComponentTransferFuncType,
1716    pub b_values: Vec<f32>,
1717    pub func_a_type: ComponentTransferFuncType,
1718    pub a_values: Vec<f32>,
1719}
1720
1721fn sanitize_func_type(
1722    func_type: ComponentTransferFuncType,
1723    values: &[f32],
1724) -> ComponentTransferFuncType {
1725    if values.is_empty() {
1726        return ComponentTransferFuncType::Identity;
1727    }
1728    if values.len() < 2 && func_type == ComponentTransferFuncType::Linear {
1729        return ComponentTransferFuncType::Identity;
1730    }
1731    if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma {
1732        return ComponentTransferFuncType::Identity;
1733    }
1734    func_type
1735}
1736
1737fn sanitize_values(
1738    func_type: ComponentTransferFuncType,
1739    values: &[f32],
1740) -> bool {
1741    if values.len() < 2 && func_type == ComponentTransferFuncType::Linear {
1742        return false;
1743    }
1744    if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma {
1745        return false;
1746    }
1747    true
1748}
1749
1750impl FilterData {
1751    /// Ensure that the number of values matches up with the function type.
1752    pub fn sanitize(&self) -> FilterData {
1753        FilterData {
1754            func_r_type: sanitize_func_type(self.func_r_type, &self.r_values),
1755            r_values:
1756                    if sanitize_values(self.func_r_type, &self.r_values) {
1757                        self.r_values.clone()
1758                    } else {
1759                        Vec::new()
1760                    },
1761            func_g_type: sanitize_func_type(self.func_g_type, &self.g_values),
1762            g_values:
1763                    if sanitize_values(self.func_g_type, &self.g_values) {
1764                        self.g_values.clone()
1765                    } else {
1766                        Vec::new()
1767                    },
1768
1769            func_b_type: sanitize_func_type(self.func_b_type, &self.b_values),
1770            b_values:
1771                    if sanitize_values(self.func_b_type, &self.b_values) {
1772                        self.b_values.clone()
1773                    } else {
1774                        Vec::new()
1775                    },
1776
1777            func_a_type: sanitize_func_type(self.func_a_type, &self.a_values),
1778            a_values:
1779                    if sanitize_values(self.func_a_type, &self.a_values) {
1780                        self.a_values.clone()
1781                    } else {
1782                        Vec::new()
1783                    },
1784
1785        }
1786    }
1787
1788    pub fn is_identity(&self) -> bool {
1789        self.func_r_type == ComponentTransferFuncType::Identity &&
1790        self.func_g_type == ComponentTransferFuncType::Identity &&
1791        self.func_b_type == ComponentTransferFuncType::Identity &&
1792        self.func_a_type == ComponentTransferFuncType::Identity
1793    }
1794}
1795
1796#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1797pub struct IframeDisplayItem {
1798    pub bounds: LayoutRect,
1799    pub clip_rect: LayoutRect,
1800    pub space_and_clip: SpaceAndClipInfo,
1801    pub pipeline_id: PipelineId,
1802    pub ignore_missing_pipeline: bool,
1803}
1804
1805/// This describes an image that fills the specified area. It stretches or shrinks
1806/// the image as necessary. While RepeatingImageDisplayItem could otherwise provide
1807/// a superset of the functionality, it has been problematic inferring the desired
1808/// repetition properties when snapping changes the size of the primitive.
1809#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1810pub struct ImageDisplayItem {
1811    pub common: CommonItemProperties,
1812    /// The area to tile the image over (first tile starts at origin of this rect)
1813    // FIXME: this should ideally just be `tile_origin` here, with the clip_rect
1814    // defining the bounds of the item. Needs non-trivial backend changes.
1815    pub bounds: LayoutRect,
1816    pub image_key: ImageKey,
1817    pub image_rendering: ImageRendering,
1818    pub alpha_type: AlphaType,
1819    /// A hack used by gecko to color a simple bitmap font used for tofu glyphs
1820    pub color: ColorF,
1821}
1822
1823/// This describes a background-image and its tiling. It repeats in a grid to fill
1824/// the specified area.
1825#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1826pub struct RepeatingImageDisplayItem {
1827    pub common: CommonItemProperties,
1828    /// The area to tile the image over (first tile starts at origin of this rect)
1829    // FIXME: this should ideally just be `tile_origin` here, with the clip_rect
1830    // defining the bounds of the item. Needs non-trivial backend changes.
1831    pub bounds: LayoutRect,
1832    /// How large to make a single tile of the image (common case: bounds.size)
1833    pub stretch_size: LayoutSize,
1834    /// The space between tiles (common case: 0)
1835    pub tile_spacing: LayoutSize,
1836    pub image_key: ImageKey,
1837    pub image_rendering: ImageRendering,
1838    pub alpha_type: AlphaType,
1839    /// A hack used by gecko to color a simple bitmap font used for tofu glyphs
1840    pub color: ColorF,
1841}
1842
1843#[repr(u8)]
1844#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1845pub enum ImageRendering {
1846    Auto = 0,
1847    CrispEdges = 1,
1848    Pixelated = 2,
1849}
1850
1851#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1852pub enum AlphaType {
1853    Alpha = 0,
1854    PremultipliedAlpha = 1,
1855}
1856
1857#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1858pub struct YuvImageDisplayItem {
1859    pub common: CommonItemProperties,
1860    pub bounds: LayoutRect,
1861    pub yuv_data: YuvData,
1862    pub color_depth: ColorDepth,
1863    pub color_space: YuvColorSpace,
1864    pub color_range: ColorRange,
1865    pub image_rendering: ImageRendering,
1866}
1867
1868#[repr(u8)]
1869#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1870pub enum YuvColorSpace {
1871    Rec601 = 0,
1872    Rec709 = 1,
1873    Rec2020 = 2,
1874    Identity = 3, // aka GBR as per ISO/IEC 23091-2:2019
1875}
1876
1877#[repr(u8)]
1878#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1879pub enum ColorRange {
1880    Limited = 0,
1881    Full = 1,
1882}
1883
1884#[repr(u8)]
1885#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1886pub enum YuvRangedColorSpace {
1887    Rec601Narrow = 0,
1888    Rec601Full = 1,
1889    Rec709Narrow = 2,
1890    Rec709Full = 3,
1891    Rec2020Narrow = 4,
1892    Rec2020Full = 5,
1893    GbrIdentity = 6,
1894}
1895
1896impl YuvColorSpace {
1897    pub fn with_range(self, range: ColorRange) -> YuvRangedColorSpace {
1898        match self {
1899            YuvColorSpace::Identity => YuvRangedColorSpace::GbrIdentity,
1900            YuvColorSpace::Rec601 => {
1901                match range {
1902                    ColorRange::Limited => YuvRangedColorSpace::Rec601Narrow,
1903                    ColorRange::Full => YuvRangedColorSpace::Rec601Full,
1904                }
1905            }
1906            YuvColorSpace::Rec709 => {
1907                match range {
1908                    ColorRange::Limited => YuvRangedColorSpace::Rec709Narrow,
1909                    ColorRange::Full => YuvRangedColorSpace::Rec709Full,
1910                }
1911            }
1912            YuvColorSpace::Rec2020 => {
1913                match range {
1914                    ColorRange::Limited => YuvRangedColorSpace::Rec2020Narrow,
1915                    ColorRange::Full => YuvRangedColorSpace::Rec2020Full,
1916                }
1917            }
1918        }
1919    }
1920}
1921
1922#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
1923pub enum YuvData {
1924    NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
1925    P010(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
1926    NV16(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
1927    PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel)
1928    InterleavedYCbCr(ImageKey), // (YCbCr interleaved channel)
1929}
1930
1931impl YuvData {
1932    pub fn get_format(&self) -> YuvFormat {
1933        match *self {
1934            YuvData::NV12(..) => YuvFormat::NV12,
1935            YuvData::P010(..) => YuvFormat::P010,
1936            YuvData::NV16(..) => YuvFormat::NV16,
1937            YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr,
1938            YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr,
1939        }
1940    }
1941}
1942
1943#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1944pub enum YuvFormat {
1945    // These enum values need to be kept in sync with yuv.glsl.
1946    NV12 = 0,
1947    P010 = 1,
1948    NV16 = 2,
1949    PlanarYCbCr = 3,
1950    InterleavedYCbCr = 4,
1951}
1952
1953impl YuvFormat {
1954    pub fn get_plane_num(self) -> usize {
1955        match self {
1956            YuvFormat::NV12 | YuvFormat::P010 | YuvFormat::NV16 => 2,
1957            YuvFormat::PlanarYCbCr => 3,
1958            YuvFormat::InterleavedYCbCr => 1,
1959        }
1960    }
1961}
1962
1963#[repr(C)]
1964#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1965pub struct ImageMask {
1966    pub image: ImageKey,
1967    pub rect: LayoutRect,
1968}
1969
1970impl ImageMask {
1971    /// Get a local clipping rect contributed by this mask.
1972    pub fn get_local_clip_rect(&self) -> Option<LayoutRect> {
1973        Some(self.rect)
1974    }
1975}
1976
1977#[repr(C)]
1978#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)]
1979pub enum ClipMode {
1980    Clip,    // Pixels inside the region are visible.
1981    ClipOut, // Pixels outside the region are visible.
1982}
1983
1984impl Not for ClipMode {
1985    type Output = ClipMode;
1986
1987    fn not(self) -> ClipMode {
1988        match self {
1989            ClipMode::Clip => ClipMode::ClipOut,
1990            ClipMode::ClipOut => ClipMode::Clip,
1991        }
1992    }
1993}
1994
1995#[repr(C)]
1996#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1997pub struct ComplexClipRegion {
1998    /// The boundaries of the rectangle.
1999    pub rect: LayoutRect,
2000    /// Border radii of this rectangle.
2001    pub radii: BorderRadius,
2002    /// Whether we are clipping inside or outside
2003    /// the region.
2004    pub mode: ClipMode,
2005}
2006
2007impl BorderRadius {
2008    pub fn zero() -> BorderRadius {
2009        BorderRadius {
2010            top_left: LayoutSize::new(0.0, 0.0),
2011            top_right: LayoutSize::new(0.0, 0.0),
2012            bottom_left: LayoutSize::new(0.0, 0.0),
2013            bottom_right: LayoutSize::new(0.0, 0.0),
2014        }
2015    }
2016
2017    pub fn uniform(radius: f32) -> BorderRadius {
2018        BorderRadius {
2019            top_left: LayoutSize::new(radius, radius),
2020            top_right: LayoutSize::new(radius, radius),
2021            bottom_left: LayoutSize::new(radius, radius),
2022            bottom_right: LayoutSize::new(radius, radius),
2023        }
2024    }
2025
2026    pub fn uniform_size(radius: LayoutSize) -> BorderRadius {
2027        BorderRadius {
2028            top_left: radius,
2029            top_right: radius,
2030            bottom_left: radius,
2031            bottom_right: radius,
2032        }
2033    }
2034
2035    pub fn all_sides_uniform(&self) -> bool {
2036        let corner_is_uniform = |corner: &LayoutSize| corner.width == corner.height;
2037        corner_is_uniform(&self.top_left) &&
2038        corner_is_uniform(&self.top_right) &&
2039        corner_is_uniform(&self.bottom_right) &&
2040        corner_is_uniform(&self.bottom_left)
2041    }
2042
2043    pub fn can_use_fast_path_in(&self, rect: &LayoutRect) -> bool {
2044        if !self.all_sides_uniform() {
2045            // The fast path needs uniform sides.
2046            return false;
2047        }
2048        // The shader code that evaluates the rounded corners in the fast path relies on each
2049        // corner fitting into their quadrant of the quad. In other words the radius cannot
2050        // exceed half of the length of the sides they are on. That necessarily holds if all the
2051        // radii are the same.
2052        let tl = self.top_left.width;
2053        if tl == self.bottom_right.width && tl == self.top_right.width && tl == self.bottom_left.width {
2054            return true;
2055        }
2056        let half_size = rect.size() * 0.5;
2057        let fits = |v: f32| v <= half_size.width && v <= half_size.height;
2058        fits(tl) && fits(self.bottom_right.width) && fits(self.top_right.width) && fits(self.bottom_left.width)
2059    }
2060
2061    /// Return whether, in each corner, the radius in *either* direction is zero.
2062    /// This means that none of the corners are rounded.
2063    pub fn is_zero(&self) -> bool {
2064        let corner_is_zero = |corner: &LayoutSize| corner.width == 0.0 || corner.height == 0.0;
2065        corner_is_zero(&self.top_left) &&
2066        corner_is_zero(&self.top_right) &&
2067        corner_is_zero(&self.bottom_right) &&
2068        corner_is_zero(&self.bottom_left)
2069    }
2070}
2071
2072impl ComplexClipRegion {
2073    /// Create a new complex clip region.
2074    pub fn new(
2075        rect: LayoutRect,
2076        radii: BorderRadius,
2077        mode: ClipMode,
2078    ) -> Self {
2079        ComplexClipRegion { rect, radii, mode }
2080    }
2081}
2082
2083impl ComplexClipRegion {
2084    /// Get a local clipping rect contributed by this clip region.
2085    pub fn get_local_clip_rect(&self) -> Option<LayoutRect> {
2086        match self.mode {
2087            ClipMode::Clip => {
2088                Some(self.rect)
2089            }
2090            ClipMode::ClipOut => {
2091                None
2092            }
2093        }
2094    }
2095}
2096
2097pub const POLYGON_CLIP_VERTEX_MAX: usize = 32;
2098
2099#[repr(u8)]
2100#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
2101pub enum FillRule {
2102    Nonzero = 0x1, // Behaves as the SVG fill-rule definition for nonzero.
2103    Evenodd = 0x2, // Behaves as the SVG fill-rule definition for evenodd.
2104}
2105
2106impl From<u8> for FillRule {
2107    fn from(fill_rule: u8) -> Self {
2108        match fill_rule {
2109            0x1 => FillRule::Nonzero,
2110            0x2 => FillRule::Evenodd,
2111            _ => panic!("Unexpected FillRule value."),
2112        }
2113    }
2114}
2115
2116impl From<FillRule> for u8 {
2117    fn from(fill_rule: FillRule) -> Self {
2118        match fill_rule {
2119            FillRule::Nonzero => 0x1,
2120            FillRule::Evenodd => 0x2,
2121        }
2122    }
2123}
2124
2125#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
2126pub struct ClipChainId(pub u64, pub PipelineId);
2127
2128impl ClipChainId {
2129    pub const INVALID: Self = ClipChainId(!0, PipelineId::INVALID);
2130}
2131
2132/// A reference to a clipping node defining how an item is clipped.
2133#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
2134pub struct ClipId(pub usize, pub PipelineId);
2135
2136impl Default for ClipId {
2137    fn default() -> Self {
2138        ClipId::invalid()
2139    }
2140}
2141
2142const ROOT_CLIP_ID: usize = 0;
2143
2144impl ClipId {
2145    /// Return the root clip ID - effectively doing no clipping.
2146    pub fn root(pipeline_id: PipelineId) -> Self {
2147        ClipId(ROOT_CLIP_ID, pipeline_id)
2148    }
2149
2150    /// Return an invalid clip ID - needed in places where we carry
2151    /// one but need to not attempt to use it.
2152    pub fn invalid() -> Self {
2153        ClipId(!0, PipelineId::dummy())
2154    }
2155
2156    pub fn pipeline_id(&self) -> PipelineId {
2157        match *self {
2158            ClipId(_, pipeline_id) => pipeline_id,
2159        }
2160    }
2161
2162    pub fn is_root(&self) -> bool {
2163        match *self {
2164            ClipId(id, _) => id == ROOT_CLIP_ID,
2165        }
2166    }
2167
2168    pub fn is_valid(&self) -> bool {
2169        match *self {
2170            ClipId(id, _) => id != !0,
2171        }
2172    }
2173}
2174
2175/// A reference to a spatial node defining item positioning.
2176#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
2177pub struct SpatialId(pub usize, PipelineId);
2178
2179const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0;
2180const ROOT_SCROLL_NODE_SPATIAL_ID: usize = 1;
2181
2182impl SpatialId {
2183    pub fn new(spatial_node_index: usize, pipeline_id: PipelineId) -> Self {
2184        SpatialId(spatial_node_index, pipeline_id)
2185    }
2186
2187    pub fn root_reference_frame(pipeline_id: PipelineId) -> Self {
2188        SpatialId(ROOT_REFERENCE_FRAME_SPATIAL_ID, pipeline_id)
2189    }
2190
2191    pub fn root_scroll_node(pipeline_id: PipelineId) -> Self {
2192        SpatialId(ROOT_SCROLL_NODE_SPATIAL_ID, pipeline_id)
2193    }
2194
2195    pub fn pipeline_id(&self) -> PipelineId {
2196        self.1
2197    }
2198}
2199
2200/// An external identifier that uniquely identifies a scroll frame independent of its ClipId, which
2201/// may change from frame to frame. This should be unique within a pipeline. WebRender makes no
2202/// attempt to ensure uniqueness. The zero value is reserved for use by the root scroll node of
2203/// every pipeline, which always has an external id.
2204///
2205/// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll
2206/// offsets between different sets of SpatialNodes which are ScrollFrames.
2207#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
2208#[repr(C)]
2209pub struct ExternalScrollId(pub u64, pub PipelineId);
2210
2211impl ExternalScrollId {
2212    pub fn pipeline_id(&self) -> PipelineId {
2213        self.1
2214    }
2215
2216    pub fn is_root(&self) -> bool {
2217        self.0 == 0
2218    }
2219}
2220
2221impl DisplayItem {
2222    pub fn debug_name(&self) -> &'static str {
2223        match *self {
2224            DisplayItem::Border(..) => "border",
2225            DisplayItem::BoxShadow(..) => "box_shadow",
2226            DisplayItem::HitTest(..) => "hit_test",
2227            DisplayItem::RectClip(..) => "rect_clip",
2228            DisplayItem::RoundedRectClip(..) => "rounded_rect_clip",
2229            DisplayItem::ImageMaskClip(..) => "image_mask_clip",
2230            DisplayItem::ClipChain(..) => "clip_chain",
2231            DisplayItem::ConicGradient(..) => "conic_gradient",
2232            DisplayItem::Gradient(..) => "gradient",
2233            DisplayItem::Iframe(..) => "iframe",
2234            DisplayItem::Image(..) => "image",
2235            DisplayItem::RepeatingImage(..) => "repeating_image",
2236            DisplayItem::Line(..) => "line",
2237            DisplayItem::PopAllShadows => "pop_all_shadows",
2238            DisplayItem::PopReferenceFrame => "pop_reference_frame",
2239            DisplayItem::PopStackingContext => "pop_stacking_context",
2240            DisplayItem::PushShadow(..) => "push_shadow",
2241            DisplayItem::PushReferenceFrame(..) => "push_reference_frame",
2242            DisplayItem::PushStackingContext(..) => "push_stacking_context",
2243            DisplayItem::SetFilterOps => "set_filter_ops",
2244            DisplayItem::SetFilterData => "set_filter_data",
2245            DisplayItem::SetPoints => "set_points",
2246            DisplayItem::RadialGradient(..) => "radial_gradient",
2247            DisplayItem::Rectangle(..) => "rectangle",
2248            DisplayItem::SetGradientStops => "set_gradient_stops",
2249            DisplayItem::Text(..) => "text",
2250            DisplayItem::YuvImage(..) => "yuv_image",
2251            DisplayItem::BackdropFilter(..) => "backdrop_filter",
2252            DisplayItem::DebugMarker(..) => "debug",
2253        }
2254    }
2255}
2256
2257macro_rules! impl_default_for_enums {
2258    ($($enum:ident => $init:expr ),+) => {
2259        $(impl Default for $enum {
2260            #[allow(unused_imports)]
2261            fn default() -> Self {
2262                use $enum::*;
2263                $init
2264            }
2265        })*
2266    }
2267}
2268
2269impl_default_for_enums! {
2270    DisplayItem => PopStackingContext,
2271    LineOrientation => Vertical,
2272    LineStyle => Solid,
2273    RepeatMode => Stretch,
2274    NinePatchBorderSource => Image(ImageKey::default(), ImageRendering::Auto),
2275    BorderDetails => Normal(NormalBorder::default()),
2276    BorderRadiusKind => Uniform,
2277    BorderStyle => None,
2278    BoxShadowClipMode => Outset,
2279    ExtendMode => Clamp,
2280    FilterOp => Identity,
2281    ComponentTransferFuncType => Identity,
2282    ClipMode => Clip,
2283    FillRule => Nonzero,
2284    ReferenceFrameKind => Transform {
2285        is_2d_scale_translation: false,
2286        should_snap: false,
2287        paired_with_perspective: false,
2288    },
2289    Rotation => Degree0,
2290    TransformStyle => Flat,
2291    RasterSpace => Local(f32::default()),
2292    MixBlendMode => Normal,
2293    ImageRendering => Auto,
2294    AlphaType => Alpha,
2295    YuvColorSpace => Rec601,
2296    YuvRangedColorSpace => Rec601Narrow,
2297    ColorRange => Limited,
2298    YuvData => NV12(ImageKey::default(), ImageKey::default()),
2299    YuvFormat => NV12,
2300    FilterPrimitiveInput => Original,
2301    ColorSpace => Srgb,
2302    CompositeOperator => Over
2303}