1use euclid::{SideOffsets2D, Angle};
6use peek_poke::PeekPoke;
7use std::ops::Not;
8use 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
17pub type ItemTag = (u64, u16);
33
34pub type ItemKey = u16;
37
38#[repr(C)]
39#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)]
40pub struct PrimitiveFlags(u8);
41
42bitflags! {
43 impl PrimitiveFlags: u8 {
44 const IS_BACKFACE_VISIBLE = 1 << 0;
46 const IS_SCROLLBAR_CONTAINER = 1 << 1;
48 const PREFER_COMPOSITOR_SURFACE = 1 << 2;
52 const SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE = 1 << 3;
56 const ANTIALISED = 1 << 4;
58 const CHECKERBOARD_BACKGROUND = 1 << 5;
60 }
61}
62
63impl core::fmt::Debug for PrimitiveFlags {
64 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
65 if self.is_empty() {
66 write!(f, "{:#x}", Self::empty().bits())
67 } else {
68 bitflags::parser::to_writer(self, f)
69 }
70 }
71}
72
73impl Default for PrimitiveFlags {
74 fn default() -> Self {
75 PrimitiveFlags::IS_BACKFACE_VISIBLE
76 }
77}
78
79#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
82pub struct CommonItemProperties {
83 pub clip_rect: LayoutRect,
87 pub clip_chain_id: ClipChainId,
89 pub spatial_id: SpatialId,
91 pub flags: PrimitiveFlags,
93}
94
95impl CommonItemProperties {
96 pub fn new(
98 clip_rect: LayoutRect,
99 space_and_clip: SpaceAndClipInfo,
100 ) -> Self {
101 Self {
102 clip_rect,
103 spatial_id: space_and_clip.spatial_id,
104 clip_chain_id: space_and_clip.clip_chain_id,
105 flags: PrimitiveFlags::default(),
106 }
107 }
108}
109
110#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
117pub struct SpaceAndClipInfo {
118 pub spatial_id: SpatialId,
119 pub clip_chain_id: ClipChainId,
120}
121
122impl SpaceAndClipInfo {
123 pub fn root_scroll(pipeline_id: PipelineId) -> Self {
126 SpaceAndClipInfo {
127 spatial_id: SpatialId::root_scroll_node(pipeline_id),
128 clip_chain_id: ClipChainId::INVALID,
129 }
130 }
131}
132
133#[repr(C)]
138#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke, Default, Eq, Hash)]
139pub struct SpatialTreeItemKey {
140 key0: u64,
141 key1: u64,
142}
143
144impl SpatialTreeItemKey {
145 pub fn new(key0: u64, key1: u64) -> Self {
146 SpatialTreeItemKey {
147 key0,
148 key1,
149 }
150 }
151}
152
153#[repr(u8)]
154#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
155pub enum SpatialTreeItem {
156 ScrollFrame(ScrollFrameDescriptor),
157 ReferenceFrame(ReferenceFrameDescriptor),
158 StickyFrame(StickyFrameDescriptor),
159 Invalid,
160}
161
162#[repr(u8)]
163#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
164pub enum DisplayItem {
165 Rectangle(RectangleDisplayItem),
167 ClearRectangle(ClearRectangleDisplayItem),
168 HitTest(HitTestDisplayItem),
169 Text(TextDisplayItem),
170 Line(LineDisplayItem),
171 Border(BorderDisplayItem),
172 BoxShadow(BoxShadowDisplayItem),
173 PushShadow(PushShadowDisplayItem),
174 Gradient(GradientDisplayItem),
175 RadialGradient(RadialGradientDisplayItem),
176 ConicGradient(ConicGradientDisplayItem),
177 Image(ImageDisplayItem),
178 RepeatingImage(RepeatingImageDisplayItem),
179 YuvImage(YuvImageDisplayItem),
180 BackdropFilter(BackdropFilterDisplayItem),
181
182 RectClip(RectClipDisplayItem),
184 RoundedRectClip(RoundedRectClipDisplayItem),
185 ImageMaskClip(ImageMaskClipDisplayItem),
186 ClipChain(ClipChainItem),
187
188 Iframe(IframeDisplayItem),
190 PushReferenceFrame(ReferenceFrameDisplayListItem),
191 PushStackingContext(PushStackingContextDisplayItem),
192
193 SetGradientStops,
196 SetFilterOps,
197 SetFilterData,
198 SetFilterPrimitives,
199 SetPoints,
200
201 PopReferenceFrame,
203 PopStackingContext,
204 PopAllShadows,
205
206 ReuseItems(ItemKey),
207 RetainedItems(ItemKey),
208
209 DebugMarker(u32),
211}
212
213#[cfg(any(feature = "serialize", feature = "deserialize"))]
216#[cfg_attr(feature = "serialize", derive(Serialize))]
217#[cfg_attr(feature = "deserialize", derive(Deserialize))]
218pub enum DebugDisplayItem {
219 Rectangle(RectangleDisplayItem),
220 ClearRectangle(ClearRectangleDisplayItem),
221 HitTest(HitTestDisplayItem),
222 Text(TextDisplayItem, Vec<font::GlyphInstance>),
223 Line(LineDisplayItem),
224 Border(BorderDisplayItem),
225 BoxShadow(BoxShadowDisplayItem),
226 PushShadow(PushShadowDisplayItem),
227 Gradient(GradientDisplayItem),
228 RadialGradient(RadialGradientDisplayItem),
229 ConicGradient(ConicGradientDisplayItem),
230 Image(ImageDisplayItem),
231 RepeatingImage(RepeatingImageDisplayItem),
232 YuvImage(YuvImageDisplayItem),
233 BackdropFilter(BackdropFilterDisplayItem),
234
235 ImageMaskClip(ImageMaskClipDisplayItem),
236 RoundedRectClip(RoundedRectClipDisplayItem),
237 RectClip(RectClipDisplayItem),
238 ClipChain(ClipChainItem, Vec<ClipId>),
239
240 Iframe(IframeDisplayItem),
241 PushReferenceFrame(ReferenceFrameDisplayListItem),
242 PushStackingContext(PushStackingContextDisplayItem),
243
244 SetGradientStops(Vec<GradientStop>),
245 SetFilterOps(Vec<FilterOp>),
246 SetFilterData(FilterData),
247 SetFilterPrimitives(Vec<FilterPrimitive>),
248 SetPoints(Vec<LayoutPoint>),
249
250 PopReferenceFrame,
251 PopStackingContext,
252 PopAllShadows,
253
254 DebugMarker(u32)
255}
256
257#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
258pub struct ImageMaskClipDisplayItem {
259 pub id: ClipId,
260 pub spatial_id: SpatialId,
261 pub image_mask: ImageMask,
262 pub fill_rule: FillRule,
263} #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
266pub struct RectClipDisplayItem {
267 pub id: ClipId,
268 pub spatial_id: SpatialId,
269 pub clip_rect: LayoutRect,
270}
271
272#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
273pub struct RoundedRectClipDisplayItem {
274 pub id: ClipId,
275 pub spatial_id: SpatialId,
276 pub clip: ComplexClipRegion,
277}
278
279#[repr(C)]
281#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
282pub struct StickyOffsetBounds {
283 pub min: f32,
287
288 pub max: f32,
292}
293
294impl StickyOffsetBounds {
295 pub fn new(min: f32, max: f32) -> StickyOffsetBounds {
296 StickyOffsetBounds { min, max }
297 }
298}
299
300#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
301pub struct StickyFrameDescriptor {
302 pub id: SpatialId,
303 pub parent_spatial_id: SpatialId,
304 pub bounds: LayoutRect,
305
306 pub margins: SideOffsets2D<Option<f32>, LayoutPixel>,
310
311 pub vertical_offset_bounds: StickyOffsetBounds,
316
317 pub horizontal_offset_bounds: StickyOffsetBounds,
322
323 pub previously_applied_offset: LayoutVector2D,
329
330 pub key: SpatialTreeItemKey,
332
333 pub transform: Option<PropertyBinding<LayoutTransform>>,
335}
336
337#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
338pub struct ScrollFrameDescriptor {
339 pub scroll_frame_id: SpatialId,
341 pub content_rect: LayoutRect,
344 pub frame_rect: LayoutRect,
345 pub parent_space: SpatialId,
346 pub external_id: ExternalScrollId,
347 pub external_scroll_offset: LayoutVector2D,
353 pub scroll_offset_generation: APZScrollGeneration,
355 pub has_scroll_linked_effect: HasScrollLinkedEffect,
357 pub key: SpatialTreeItemKey,
359}
360
361#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
363pub struct RectangleDisplayItem {
364 pub common: CommonItemProperties,
365 pub bounds: LayoutRect,
366 pub color: PropertyBinding<ColorF>,
367}
368
369#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
372pub struct ClearRectangleDisplayItem {
373 pub common: CommonItemProperties,
374 pub bounds: LayoutRect,
375}
376
377#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
381pub struct HitTestDisplayItem {
382 pub rect: LayoutRect,
383 pub clip_chain_id: ClipChainId,
384 pub spatial_id: SpatialId,
385 pub flags: PrimitiveFlags,
386 pub tag: ItemTag,
387}
388
389#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
390pub struct LineDisplayItem {
391 pub common: CommonItemProperties,
392 pub area: LayoutRect,
398 pub orientation: LineOrientation,
400 pub wavy_line_thickness: f32,
406 pub color: ColorF,
407 pub style: LineStyle,
408}
409
410#[repr(u8)]
411#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
412pub enum LineOrientation {
413 Vertical,
414 Horizontal,
415}
416
417#[repr(u8)]
418#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
419pub enum LineStyle {
420 Solid,
421 Dotted,
422 Dashed,
423 Wavy,
424}
425
426#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
427pub struct TextDisplayItem {
428 pub common: CommonItemProperties,
429 pub bounds: LayoutRect,
437 pub font_key: font::FontInstanceKey,
438 pub color: ColorF,
439 pub glyph_options: Option<font::GlyphOptions>,
440 pub ref_frame_offset: LayoutVector2D,
441} #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
444pub struct NormalBorder {
445 pub left: BorderSide,
446 pub right: BorderSide,
447 pub top: BorderSide,
448 pub bottom: BorderSide,
449 pub radius: BorderRadius,
450 pub do_aa: bool,
455}
456
457impl NormalBorder {
458 fn can_disable_antialiasing(&self) -> bool {
459 fn is_valid(style: BorderStyle) -> bool {
460 style == BorderStyle::Solid || style == BorderStyle::None
461 }
462
463 self.radius.is_zero() &&
464 is_valid(self.top.style) &&
465 is_valid(self.left.style) &&
466 is_valid(self.bottom.style) &&
467 is_valid(self.right.style)
468 }
469
470 #[inline]
473 pub fn normalize(&mut self, widths: &LayoutSideOffsets) {
474 debug_assert!(
475 self.do_aa || self.can_disable_antialiasing(),
476 "Unexpected disabled-antialiasing in a border, likely won't work or will be ignored"
477 );
478
479 #[inline]
480 fn renders_small_border_solid(style: BorderStyle) -> bool {
481 match style {
482 BorderStyle::Groove |
483 BorderStyle::Ridge => true,
484 _ => false,
485 }
486 }
487
488 let normalize_side = |side: &mut BorderSide, width: f32| {
489 if renders_small_border_solid(side.style) && width < 2. {
490 side.style = BorderStyle::Solid;
491 }
492 };
493
494 normalize_side(&mut self.left, widths.left);
495 normalize_side(&mut self.right, widths.right);
496 normalize_side(&mut self.top, widths.top);
497 normalize_side(&mut self.bottom, widths.bottom);
498 }
499}
500
501#[repr(u8)]
502#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)]
503pub enum RepeatMode {
504 Stretch,
505 Repeat,
506 Round,
507 Space,
508}
509
510#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
511pub enum NinePatchBorderSource {
512 Image(ImageKey, ImageRendering),
513 Gradient(Gradient),
514 RadialGradient(RadialGradient),
515 ConicGradient(ConicGradient),
516}
517
518#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
519pub struct NinePatchBorder {
520 pub source: NinePatchBorderSource,
523
524 pub width: i32,
526
527 pub height: i32,
529
530 pub slice: DeviceIntSideOffsets,
538
539 pub fill: bool,
542
543 pub repeat_horizontal: RepeatMode,
546
547 pub repeat_vertical: RepeatMode,
550}
551
552#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
553pub enum BorderDetails {
554 Normal(NormalBorder),
555 NinePatch(NinePatchBorder),
556}
557
558#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
559pub struct BorderDisplayItem {
560 pub common: CommonItemProperties,
561 pub bounds: LayoutRect,
562 pub widths: LayoutSideOffsets,
563 pub details: BorderDetails,
564}
565
566#[repr(C)]
567#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
568pub enum BorderRadiusKind {
569 Uniform,
570 NonUniform,
571}
572
573#[repr(C)]
574#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
575pub struct BorderRadius {
576 pub top_left: LayoutSize,
577 pub top_right: LayoutSize,
578 pub bottom_left: LayoutSize,
579 pub bottom_right: LayoutSize,
580}
581
582impl Default for BorderRadius {
583 fn default() -> Self {
584 BorderRadius {
585 top_left: LayoutSize::zero(),
586 top_right: LayoutSize::zero(),
587 bottom_left: LayoutSize::zero(),
588 bottom_right: LayoutSize::zero(),
589 }
590 }
591}
592
593#[repr(C)]
594#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
595pub struct BorderSide {
596 pub color: ColorF,
597 pub style: BorderStyle,
598}
599
600#[repr(u32)]
601#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq, PeekPoke)]
602pub enum BorderStyle {
603 None = 0,
604 Solid = 1,
605 Double = 2,
606 Dotted = 3,
607 Dashed = 4,
608 Hidden = 5,
609 Groove = 6,
610 Ridge = 7,
611 Inset = 8,
612 Outset = 9,
613}
614
615impl BorderStyle {
616 pub fn is_hidden(self) -> bool {
617 self == BorderStyle::Hidden || self == BorderStyle::None
618 }
619}
620
621#[repr(u8)]
622#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
623pub enum BoxShadowClipMode {
624 Outset = 0,
625 Inset = 1,
626}
627
628#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
629pub struct BoxShadowDisplayItem {
630 pub common: CommonItemProperties,
631 pub box_bounds: LayoutRect,
632 pub offset: LayoutVector2D,
633 pub color: ColorF,
634 pub blur_radius: f32,
635 pub spread_radius: f32,
636 pub border_radius: BorderRadius,
637 pub clip_mode: BoxShadowClipMode,
638}
639
640#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
641pub struct PushShadowDisplayItem {
642 pub space_and_clip: SpaceAndClipInfo,
643 pub shadow: Shadow,
644 pub should_inflate: bool,
645}
646
647#[repr(C)]
648#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
649pub struct Shadow {
650 pub offset: LayoutVector2D,
651 pub color: ColorF,
652 pub blur_radius: f32,
653}
654
655#[repr(u8)]
656#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)]
657pub enum ExtendMode {
658 Clamp,
659 Repeat,
660}
661
662#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
663pub struct Gradient {
664 pub start_point: LayoutPoint,
665 pub end_point: LayoutPoint,
666 pub extend_mode: ExtendMode,
667} impl Gradient {
670 pub fn is_valid(&self) -> bool {
671 self.start_point.x.is_finite() &&
672 self.start_point.y.is_finite() &&
673 self.end_point.x.is_finite() &&
674 self.end_point.y.is_finite()
675 }
676}
677
678#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
680pub struct GradientDisplayItem {
681 pub common: CommonItemProperties,
683 pub bounds: LayoutRect,
687 pub tile_size: LayoutSize,
689 pub tile_spacing: LayoutSize,
691 pub gradient: Gradient,
692}
693
694#[repr(C)]
695#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
696pub struct GradientStop {
697 pub offset: f32,
698 pub color: ColorF,
699}
700
701#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
702pub struct RadialGradient {
703 pub center: LayoutPoint,
704 pub radius: LayoutSize,
705 pub start_offset: f32,
706 pub end_offset: f32,
707 pub extend_mode: ExtendMode,
708} impl RadialGradient {
711 pub fn is_valid(&self) -> bool {
712 self.center.x.is_finite() &&
713 self.center.y.is_finite() &&
714 self.start_offset.is_finite() &&
715 self.end_offset.is_finite()
716 }
717}
718
719#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
720pub struct ConicGradient {
721 pub center: LayoutPoint,
722 pub angle: f32,
723 pub start_offset: f32,
724 pub end_offset: f32,
725 pub extend_mode: ExtendMode,
726} impl ConicGradient {
729 pub fn is_valid(&self) -> bool {
730 self.center.x.is_finite() &&
731 self.center.y.is_finite() &&
732 self.angle.is_finite() &&
733 self.start_offset.is_finite() &&
734 self.end_offset.is_finite()
735 }
736}
737
738#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
740pub struct ClipChainItem {
741 pub id: ClipChainId,
742 pub parent: Option<ClipChainId>,
743} #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
746pub struct RadialGradientDisplayItem {
747 pub common: CommonItemProperties,
748 pub bounds: LayoutRect,
752 pub gradient: RadialGradient,
753 pub tile_size: LayoutSize,
754 pub tile_spacing: LayoutSize,
755}
756
757#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
758pub struct ConicGradientDisplayItem {
759 pub common: CommonItemProperties,
760 pub bounds: LayoutRect,
764 pub gradient: ConicGradient,
765 pub tile_size: LayoutSize,
766 pub tile_spacing: LayoutSize,
767}
768
769#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
771pub struct BackdropFilterDisplayItem {
772 pub common: CommonItemProperties,
773}
774#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
777pub struct ReferenceFrameDisplayListItem {
778}
779
780#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
781pub struct ReferenceFrameDescriptor {
782 pub origin: LayoutPoint,
783 pub parent_spatial_id: SpatialId,
784 pub reference_frame: ReferenceFrame,
785}
786
787#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
788pub enum ReferenceFrameKind {
789 Transform {
791 is_2d_scale_translation: bool,
794 should_snap: bool,
797 paired_with_perspective: bool,
801 },
802 Perspective {
804 scrolling_relative_to: Option<ExternalScrollId>,
805 }
806}
807
808#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
809pub enum Rotation {
810 Degree0,
811 Degree90,
812 Degree180,
813 Degree270,
814}
815
816impl Rotation {
817 pub fn to_matrix(
818 &self,
819 size: LayoutSize,
820 ) -> LayoutTransform {
821 let (shift_center_to_origin, angle) = match self {
822 Rotation::Degree0 => {
823 (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.))
824 },
825 Rotation::Degree90 => {
826 (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.))
827 },
828 Rotation::Degree180 => {
829 (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.))
830 },
831 Rotation::Degree270 => {
832 (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.))
833 },
834 };
835 let shift_origin_to_center = LayoutTransform::translation(size.width / 2., size.height / 2., 0.);
836
837 shift_center_to_origin
838 .then(&LayoutTransform::rotation(0., 0., 1.0, angle))
839 .then(&shift_origin_to_center)
840 }
841}
842
843#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
844pub enum ReferenceTransformBinding {
845 Static {
847 binding: PropertyBinding<LayoutTransform>,
848 },
849 Computed {
858 scale_from: Option<LayoutSize>,
859 vertical_flip: bool,
860 rotation: Rotation,
861 },
862}
863
864impl Default for ReferenceTransformBinding {
865 fn default() -> Self {
866 ReferenceTransformBinding::Static {
867 binding: Default::default(),
868 }
869 }
870}
871
872#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
873pub struct ReferenceFrame {
874 pub kind: ReferenceFrameKind,
875 pub transform_style: TransformStyle,
876 pub transform: ReferenceTransformBinding,
879 pub id: SpatialId,
880 pub key: SpatialTreeItemKey,
882}
883
884#[repr(C)]
897#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
898pub struct SnapshotInfo {
899 pub key: SnapshotImageKey,
901 pub area: LayoutRect,
906 pub detached: bool,
911}
912
913#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
914pub struct PushStackingContextDisplayItem {
915 pub origin: LayoutPoint,
916 pub spatial_id: SpatialId,
917 pub snapshot: Option<SnapshotInfo>,
918 pub prim_flags: PrimitiveFlags,
919 pub ref_frame_offset: LayoutVector2D,
920 pub stacking_context: StackingContext,
921}
922
923#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
924pub struct StackingContext {
925 pub transform_style: TransformStyle,
926 pub mix_blend_mode: MixBlendMode,
927 pub clip_chain_id: Option<ClipChainId>,
928 pub raster_space: RasterSpace,
929 pub flags: StackingContextFlags,
930}
931#[repr(u8)]
934#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
935pub enum TransformStyle {
936 Flat = 0,
937 Preserve3D = 1,
938}
939
940#[derive(Clone, Copy, Debug, Deserialize, PartialEq, MallocSizeOf, Serialize, PeekPoke)]
947#[repr(u8)]
948pub enum RasterSpace {
949 Local(f32),
952
953 Screen,
958}
959
960impl RasterSpace {
961 pub fn local_scale(self) -> Option<f32> {
962 match self {
963 RasterSpace::Local(scale) => Some(scale),
964 RasterSpace::Screen => None,
965 }
966 }
967}
968
969impl Eq for RasterSpace {}
970
971impl Hash for RasterSpace {
972 fn hash<H: Hasher>(&self, state: &mut H) {
973 match self {
974 RasterSpace::Screen => {
975 0.hash(state);
976 }
977 RasterSpace::Local(scale) => {
978 1.hash(state);
980 scale.to_bits().hash(state);
981 }
982 }
983 }
984}
985
986#[repr(C)]
987#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)]
988pub struct StackingContextFlags(u8);
989
990bitflags! {
991 impl StackingContextFlags: u8 {
992 const IS_BLEND_CONTAINER = 1 << 0;
995 const WRAPS_BACKDROP_FILTER = 1 << 1;
999 const FORCED_ISOLATION = 1 << 2;
1001 }
1002}
1003
1004impl core::fmt::Debug for StackingContextFlags {
1005 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1006 if self.is_empty() {
1007 write!(f, "{:#x}", Self::empty().bits())
1008 } else {
1009 bitflags::parser::to_writer(self, f)
1010 }
1011 }
1012}
1013
1014impl Default for StackingContextFlags {
1015 fn default() -> Self {
1016 StackingContextFlags::empty()
1017 }
1018}
1019
1020#[repr(u8)]
1021#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1022pub enum MixBlendMode {
1023 Normal = 0,
1024 Multiply = 1,
1025 Screen = 2,
1026 Overlay = 3,
1027 Darken = 4,
1028 Lighten = 5,
1029 ColorDodge = 6,
1030 ColorBurn = 7,
1031 HardLight = 8,
1032 SoftLight = 9,
1033 Difference = 10,
1034 Exclusion = 11,
1035 Hue = 12,
1036 Saturation = 13,
1037 Color = 14,
1038 Luminosity = 15,
1039 PlusLighter = 16,
1040}
1041
1042#[repr(C)]
1043#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1044pub enum ColorSpace {
1045 Srgb,
1046 LinearRgb,
1047}
1048
1049#[repr(C)]
1051#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1052pub enum CompositeOperator {
1053 Over,
1054 In,
1055 Atop,
1056 Out,
1057 Xor,
1058 Lighter,
1059 Arithmetic([f32; 4]),
1060}
1061
1062impl CompositeOperator {
1063 pub fn as_int(&self) -> u32 {
1065 match self {
1066 CompositeOperator::Over => 0,
1067 CompositeOperator::In => 1,
1068 CompositeOperator::Out => 2,
1069 CompositeOperator::Atop => 3,
1070 CompositeOperator::Xor => 4,
1071 CompositeOperator::Lighter => 5,
1072 CompositeOperator::Arithmetic(..) => 6,
1073 }
1074 }
1075}
1076
1077#[repr(C)]
1079#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1080pub enum FilterPrimitiveInput {
1081 Original,
1083 Previous,
1085 OutputOfPrimitiveIndex(usize),
1087}
1088
1089impl FilterPrimitiveInput {
1090 pub fn to_index(self, cur_index: usize) -> Option<usize> {
1093 match self {
1094 FilterPrimitiveInput::Previous if cur_index > 0 => Some(cur_index - 1),
1095 FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => Some(index),
1096 _ => None,
1097 }
1098 }
1099}
1100
1101#[repr(C)]
1102#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1103pub struct BlendPrimitive {
1104 pub input1: FilterPrimitiveInput,
1105 pub input2: FilterPrimitiveInput,
1106 pub mode: MixBlendMode,
1107}
1108
1109#[repr(C)]
1110#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1111pub struct FloodPrimitive {
1112 pub color: ColorF,
1113}
1114
1115impl FloodPrimitive {
1116 pub fn sanitize(&mut self) {
1117 self.color.r = self.color.r.clamp(0.0, 1.0);
1118 self.color.g = self.color.g.clamp(0.0, 1.0);
1119 self.color.b = self.color.b.clamp(0.0, 1.0);
1120 self.color.a = self.color.a.clamp(0.0, 1.0);
1121 }
1122}
1123
1124#[repr(C)]
1125#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1126pub struct BlurPrimitive {
1127 pub input: FilterPrimitiveInput,
1128 pub width: f32,
1129 pub height: f32,
1130}
1131
1132#[repr(C)]
1133#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1134pub struct OpacityPrimitive {
1135 pub input: FilterPrimitiveInput,
1136 pub opacity: f32,
1137}
1138
1139impl OpacityPrimitive {
1140 pub fn sanitize(&mut self) {
1141 self.opacity = self.opacity.clamp(0.0, 1.0);
1142 }
1143}
1144
1145#[repr(C)]
1147#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1148pub struct ColorMatrixPrimitive {
1149 pub input: FilterPrimitiveInput,
1150 pub matrix: [f32; 20],
1151}
1152
1153#[repr(C)]
1154#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1155pub struct DropShadowPrimitive {
1156 pub input: FilterPrimitiveInput,
1157 pub shadow: Shadow,
1158}
1159
1160#[repr(C)]
1161#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1162pub struct ComponentTransferPrimitive {
1163 pub input: FilterPrimitiveInput,
1164 }
1166
1167#[repr(C)]
1168#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1169pub struct IdentityPrimitive {
1170 pub input: FilterPrimitiveInput,
1171}
1172
1173#[repr(C)]
1174#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1175pub struct OffsetPrimitive {
1176 pub input: FilterPrimitiveInput,
1177 pub offset: LayoutVector2D,
1178}
1179
1180#[repr(C)]
1181#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1182pub struct CompositePrimitive {
1183 pub input1: FilterPrimitiveInput,
1184 pub input2: FilterPrimitiveInput,
1185 pub operator: CompositeOperator,
1186}
1187
1188#[repr(C)]
1191#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
1192pub enum FilterPrimitiveKind {
1193 Identity(IdentityPrimitive),
1194 Blend(BlendPrimitive),
1195 Flood(FloodPrimitive),
1196 Blur(BlurPrimitive),
1197 Opacity(OpacityPrimitive),
1199 ColorMatrix(ColorMatrixPrimitive),
1201 DropShadow(DropShadowPrimitive),
1202 ComponentTransfer(ComponentTransferPrimitive),
1203 Offset(OffsetPrimitive),
1204 Composite(CompositePrimitive),
1205}
1206
1207impl Default for FilterPrimitiveKind {
1208 fn default() -> Self {
1209 FilterPrimitiveKind::Identity(IdentityPrimitive::default())
1210 }
1211}
1212
1213impl FilterPrimitiveKind {
1214 pub fn sanitize(&mut self) {
1215 match self {
1216 FilterPrimitiveKind::Flood(flood) => flood.sanitize(),
1217 FilterPrimitiveKind::Opacity(opacity) => opacity.sanitize(),
1218
1219 FilterPrimitiveKind::Identity(..) |
1221 FilterPrimitiveKind::Blend(..) |
1222 FilterPrimitiveKind::ColorMatrix(..) |
1223 FilterPrimitiveKind::Offset(..) |
1224 FilterPrimitiveKind::Composite(..) |
1225 FilterPrimitiveKind::Blur(..) |
1226 FilterPrimitiveKind::DropShadow(..) |
1227 FilterPrimitiveKind::ComponentTransfer(..) => {}
1229 }
1230 }
1231}
1232
1233#[repr(C)]
1237#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1238pub struct FilterPrimitive {
1239 pub kind: FilterPrimitiveKind,
1240 pub color_space: ColorSpace,
1241}
1242
1243impl FilterPrimitive {
1244 pub fn sanitize(&mut self) {
1245 self.kind.sanitize();
1246 }
1247}
1248
1249#[repr(C)]
1250#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, PeekPoke)]
1251pub enum FilterOpGraphPictureBufferId {
1252 #[default]
1253 None,
1255 BufferId(i16),
1257}
1258
1259#[repr(C)]
1260#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PeekPoke)]
1261pub struct FilterOpGraphPictureReference {
1262 pub buffer_id: FilterOpGraphPictureBufferId,
1264}
1265
1266#[repr(C)]
1267#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PeekPoke)]
1268pub struct FilterOpGraphNode {
1269 pub linear: bool,
1273 pub input: FilterOpGraphPictureReference,
1276 pub input2: FilterOpGraphPictureReference,
1279 pub subregion: LayoutRect,
1281}
1282
1283pub const SVGFE_GRAPH_MAX: usize = 256;
1288
1289#[repr(C)]
1290#[derive(Clone, Copy, Debug, Deserialize, Serialize, PeekPoke)]
1291pub enum FilterOp {
1292 Identity,
1297 Blur(f32, f32),
1301 Brightness(f32),
1305 Contrast(f32),
1309 Grayscale(f32),
1313 HueRotate(f32),
1317 Invert(f32),
1321 Opacity(PropertyBinding<f32>, f32),
1325 Saturate(f32),
1329 Sepia(f32),
1333 DropShadow(Shadow),
1337 ColorMatrix([f32; 20]),
1341 SrgbToLinear,
1345 LinearToSrgb,
1349 ComponentTransfer,
1353 Flood(ColorF),
1358 SVGFESourceGraphic{node: FilterOpGraphNode},
1364 SVGFESourceAlpha{node: FilterOpGraphNode},
1370 SVGFEIdentity{node: FilterOpGraphNode},
1373 SVGFEOpacity{node: FilterOpGraphNode, valuebinding: PropertyBinding<f32>, value: f32},
1378 SVGFEToAlpha{node: FilterOpGraphNode},
1381 SVGFEBlendDarken{node: FilterOpGraphNode},
1387 SVGFEBlendLighten{node: FilterOpGraphNode},
1393 SVGFEBlendMultiply{node: FilterOpGraphNode},
1399 SVGFEBlendNormal{node: FilterOpGraphNode},
1405 SVGFEBlendScreen{node: FilterOpGraphNode},
1411 SVGFEBlendOverlay{node: FilterOpGraphNode},
1417 SVGFEBlendColorDodge{node: FilterOpGraphNode},
1423 SVGFEBlendColorBurn{node: FilterOpGraphNode},
1429 SVGFEBlendHardLight{node: FilterOpGraphNode},
1435 SVGFEBlendSoftLight{node: FilterOpGraphNode},
1441 SVGFEBlendDifference{node: FilterOpGraphNode},
1447 SVGFEBlendExclusion{node: FilterOpGraphNode},
1453 SVGFEBlendHue{node: FilterOpGraphNode},
1459 SVGFEBlendSaturation{node: FilterOpGraphNode},
1465 SVGFEBlendColor{node: FilterOpGraphNode},
1471 SVGFEBlendLuminosity{node: FilterOpGraphNode},
1477 SVGFEColorMatrix{node: FilterOpGraphNode, values: [f32; 20]},
1483 SVGFEComponentTransfer{node: FilterOpGraphNode},
1489 SVGFECompositeArithmetic{node: FilterOpGraphNode, k1: f32, k2: f32, k3: f32,
1495 k4: f32},
1496 SVGFECompositeATop{node: FilterOpGraphNode},
1502 SVGFECompositeIn{node: FilterOpGraphNode},
1508 SVGFECompositeLighter{node: FilterOpGraphNode},
1514 SVGFECompositeOut{node: FilterOpGraphNode},
1520 SVGFECompositeOver{node: FilterOpGraphNode},
1526 SVGFECompositeXOR{node: FilterOpGraphNode},
1532 SVGFEConvolveMatrixEdgeModeDuplicate{node: FilterOpGraphNode, order_x: i32,
1541 order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32,
1542 target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32,
1543 preserve_alpha: i32},
1544 SVGFEConvolveMatrixEdgeModeNone{node: FilterOpGraphNode, order_x: i32,
1553 order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32,
1554 target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32,
1555 preserve_alpha: i32},
1556 SVGFEConvolveMatrixEdgeModeWrap{node: FilterOpGraphNode, order_x: i32,
1565 order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32,
1566 target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32,
1567 preserve_alpha: i32},
1568 SVGFEDiffuseLightingDistant{node: FilterOpGraphNode, surface_scale: f32,
1577 diffuse_constant: f32, kernel_unit_length_x: f32,
1578 kernel_unit_length_y: f32, azimuth: f32, elevation: f32},
1579 SVGFEDiffuseLightingPoint{node: FilterOpGraphNode, surface_scale: f32,
1588 diffuse_constant: f32, kernel_unit_length_x: f32,
1589 kernel_unit_length_y: f32, x: f32, y: f32, z: f32},
1590 SVGFEDiffuseLightingSpot{node: FilterOpGraphNode, surface_scale: f32,
1601 diffuse_constant: f32, kernel_unit_length_x: f32,
1602 kernel_unit_length_y: f32, x: f32, y: f32, z: f32, points_at_x: f32,
1603 points_at_y: f32, points_at_z: f32, cone_exponent: f32,
1604 limiting_cone_angle: f32},
1605 SVGFEDisplacementMap{node: FilterOpGraphNode, scale: f32,
1612 x_channel_selector: u32, y_channel_selector: u32},
1613 SVGFEDropShadow{node: FilterOpGraphNode, color: ColorF, dx: f32, dy: f32,
1621 std_deviation_x: f32, std_deviation_y: f32},
1622 SVGFEFlood{node: FilterOpGraphNode, color: ColorF},
1628 SVGFEGaussianBlur{node: FilterOpGraphNode, std_deviation_x: f32, std_deviation_y: f32},
1634 SVGFEImage{node: FilterOpGraphNode, sampling_filter: u32, matrix: [f32; 6]},
1640 SVGFEMorphologyDilate{node: FilterOpGraphNode, radius_x: f32, radius_y: f32},
1647 SVGFEMorphologyErode{node: FilterOpGraphNode, radius_x: f32, radius_y: f32},
1654 SVGFEOffset{node: FilterOpGraphNode, offset_x: f32, offset_y: f32},
1661 SVGFESpecularLightingDistant{node: FilterOpGraphNode, surface_scale: f32,
1670 specular_constant: f32, specular_exponent: f32,
1671 kernel_unit_length_x: f32, kernel_unit_length_y: f32, azimuth: f32,
1672 elevation: f32},
1673 SVGFESpecularLightingPoint{node: FilterOpGraphNode, surface_scale: f32,
1682 specular_constant: f32, specular_exponent: f32,
1683 kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
1684 z: f32},
1685 SVGFESpecularLightingSpot{node: FilterOpGraphNode, surface_scale: f32,
1696 specular_constant: f32, specular_exponent: f32,
1697 kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32,
1698 z: f32, points_at_x: f32, points_at_y: f32, points_at_z: f32,
1699 cone_exponent: f32, limiting_cone_angle: f32},
1700 SVGFETile{node: FilterOpGraphNode},
1707 SVGFETurbulenceWithFractalNoiseWithNoStitching{node: FilterOpGraphNode,
1715 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32,
1716 seed: u32},
1717 SVGFETurbulenceWithFractalNoiseWithStitching{node: FilterOpGraphNode,
1725 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32,
1726 seed: u32},
1727 SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{node: FilterOpGraphNode,
1734 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32,
1735 seed: u32},
1736 SVGFETurbulenceWithTurbulenceNoiseWithStitching{node: FilterOpGraphNode,
1743 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32, seed: u32},
1744}
1745
1746#[repr(u8)]
1747#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)]
1748pub enum ComponentTransferFuncType {
1749 Identity = 0,
1750 Table = 1,
1751 Discrete = 2,
1752 Linear = 3,
1753 Gamma = 4,
1754}
1755
1756#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
1757pub struct FilterData {
1758 pub func_r_type: ComponentTransferFuncType,
1760 pub r_values: Vec<f32>,
1761 pub func_g_type: ComponentTransferFuncType,
1762 pub g_values: Vec<f32>,
1763 pub func_b_type: ComponentTransferFuncType,
1764 pub b_values: Vec<f32>,
1765 pub func_a_type: ComponentTransferFuncType,
1766 pub a_values: Vec<f32>,
1767}
1768
1769fn sanitize_func_type(
1770 func_type: ComponentTransferFuncType,
1771 values: &[f32],
1772) -> ComponentTransferFuncType {
1773 if values.is_empty() {
1774 return ComponentTransferFuncType::Identity;
1775 }
1776 if values.len() < 2 && func_type == ComponentTransferFuncType::Linear {
1777 return ComponentTransferFuncType::Identity;
1778 }
1779 if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma {
1780 return ComponentTransferFuncType::Identity;
1781 }
1782 func_type
1783}
1784
1785fn sanitize_values(
1786 func_type: ComponentTransferFuncType,
1787 values: &[f32],
1788) -> bool {
1789 if values.len() < 2 && func_type == ComponentTransferFuncType::Linear {
1790 return false;
1791 }
1792 if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma {
1793 return false;
1794 }
1795 true
1796}
1797
1798impl FilterData {
1799 pub fn sanitize(&self) -> FilterData {
1801 FilterData {
1802 func_r_type: sanitize_func_type(self.func_r_type, &self.r_values),
1803 r_values:
1804 if sanitize_values(self.func_r_type, &self.r_values) {
1805 self.r_values.clone()
1806 } else {
1807 Vec::new()
1808 },
1809 func_g_type: sanitize_func_type(self.func_g_type, &self.g_values),
1810 g_values:
1811 if sanitize_values(self.func_g_type, &self.g_values) {
1812 self.g_values.clone()
1813 } else {
1814 Vec::new()
1815 },
1816
1817 func_b_type: sanitize_func_type(self.func_b_type, &self.b_values),
1818 b_values:
1819 if sanitize_values(self.func_b_type, &self.b_values) {
1820 self.b_values.clone()
1821 } else {
1822 Vec::new()
1823 },
1824
1825 func_a_type: sanitize_func_type(self.func_a_type, &self.a_values),
1826 a_values:
1827 if sanitize_values(self.func_a_type, &self.a_values) {
1828 self.a_values.clone()
1829 } else {
1830 Vec::new()
1831 },
1832
1833 }
1834 }
1835
1836 pub fn is_identity(&self) -> bool {
1837 self.func_r_type == ComponentTransferFuncType::Identity &&
1838 self.func_g_type == ComponentTransferFuncType::Identity &&
1839 self.func_b_type == ComponentTransferFuncType::Identity &&
1840 self.func_a_type == ComponentTransferFuncType::Identity
1841 }
1842}
1843
1844#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1845pub struct IframeDisplayItem {
1846 pub bounds: LayoutRect,
1847 pub clip_rect: LayoutRect,
1848 pub space_and_clip: SpaceAndClipInfo,
1849 pub pipeline_id: PipelineId,
1850 pub ignore_missing_pipeline: bool,
1851}
1852
1853#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1858pub struct ImageDisplayItem {
1859 pub common: CommonItemProperties,
1860 pub bounds: LayoutRect,
1864 pub image_key: ImageKey,
1865 pub image_rendering: ImageRendering,
1866 pub alpha_type: AlphaType,
1867 pub color: ColorF,
1869}
1870
1871#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1874pub struct RepeatingImageDisplayItem {
1875 pub common: CommonItemProperties,
1876 pub bounds: LayoutRect,
1880 pub stretch_size: LayoutSize,
1882 pub tile_spacing: LayoutSize,
1884 pub image_key: ImageKey,
1885 pub image_rendering: ImageRendering,
1886 pub alpha_type: AlphaType,
1887 pub color: ColorF,
1889}
1890
1891#[repr(u8)]
1892#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1893pub enum ImageRendering {
1894 Auto = 0,
1895 CrispEdges = 1,
1896 Pixelated = 2,
1897}
1898
1899#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1900pub enum AlphaType {
1901 Alpha = 0,
1902 PremultipliedAlpha = 1,
1903}
1904
1905#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
1906pub struct YuvImageDisplayItem {
1907 pub common: CommonItemProperties,
1908 pub bounds: LayoutRect,
1909 pub yuv_data: YuvData,
1910 pub color_depth: ColorDepth,
1911 pub color_space: YuvColorSpace,
1912 pub color_range: ColorRange,
1913 pub image_rendering: ImageRendering,
1914}
1915
1916#[repr(u8)]
1917#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1918pub enum YuvColorSpace {
1919 Rec601 = 0,
1920 Rec709 = 1,
1921 Rec2020 = 2,
1922 Identity = 3, }
1924
1925#[repr(u8)]
1926#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1927pub enum ColorRange {
1928 Limited = 0,
1929 Full = 1,
1930}
1931
1932#[repr(u8)]
1933#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1934pub enum YuvRangedColorSpace {
1935 Rec601Narrow = 0,
1936 Rec601Full = 1,
1937 Rec709Narrow = 2,
1938 Rec709Full = 3,
1939 Rec2020Narrow = 4,
1940 Rec2020Full = 5,
1941 GbrIdentity = 6,
1942}
1943
1944impl YuvColorSpace {
1945 pub fn with_range(self, range: ColorRange) -> YuvRangedColorSpace {
1946 match self {
1947 YuvColorSpace::Identity => YuvRangedColorSpace::GbrIdentity,
1948 YuvColorSpace::Rec601 => {
1949 match range {
1950 ColorRange::Limited => YuvRangedColorSpace::Rec601Narrow,
1951 ColorRange::Full => YuvRangedColorSpace::Rec601Full,
1952 }
1953 }
1954 YuvColorSpace::Rec709 => {
1955 match range {
1956 ColorRange::Limited => YuvRangedColorSpace::Rec709Narrow,
1957 ColorRange::Full => YuvRangedColorSpace::Rec709Full,
1958 }
1959 }
1960 YuvColorSpace::Rec2020 => {
1961 match range {
1962 ColorRange::Limited => YuvRangedColorSpace::Rec2020Narrow,
1963 ColorRange::Full => YuvRangedColorSpace::Rec2020Full,
1964 }
1965 }
1966 }
1967 }
1968}
1969
1970#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
1971pub enum YuvData {
1972 NV12(ImageKey, ImageKey), P010(ImageKey, ImageKey), NV16(ImageKey, ImageKey), PlanarYCbCr(ImageKey, ImageKey, ImageKey), InterleavedYCbCr(ImageKey), }
1978
1979impl YuvData {
1980 pub fn get_format(&self) -> YuvFormat {
1981 match *self {
1982 YuvData::NV12(..) => YuvFormat::NV12,
1983 YuvData::P010(..) => YuvFormat::P010,
1984 YuvData::NV16(..) => YuvFormat::NV16,
1985 YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr,
1986 YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr,
1987 }
1988 }
1989}
1990
1991#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
1992pub enum YuvFormat {
1993 NV12 = 0,
1995 P010 = 1,
1996 NV16 = 2,
1997 PlanarYCbCr = 3,
1998 InterleavedYCbCr = 4,
1999}
2000
2001impl YuvFormat {
2002 pub fn get_plane_num(self) -> usize {
2003 match self {
2004 YuvFormat::NV12 | YuvFormat::P010 | YuvFormat::NV16 => 2,
2005 YuvFormat::PlanarYCbCr => 3,
2006 YuvFormat::InterleavedYCbCr => 1,
2007 }
2008 }
2009}
2010
2011#[repr(C)]
2012#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
2013pub struct ImageMask {
2014 pub image: ImageKey,
2015 pub rect: LayoutRect,
2016}
2017
2018impl ImageMask {
2019 pub fn get_local_clip_rect(&self) -> Option<LayoutRect> {
2021 Some(self.rect)
2022 }
2023}
2024
2025#[repr(C)]
2026#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)]
2027pub enum ClipMode {
2028 Clip, ClipOut, }
2031
2032impl Not for ClipMode {
2033 type Output = ClipMode;
2034
2035 fn not(self) -> ClipMode {
2036 match self {
2037 ClipMode::Clip => ClipMode::ClipOut,
2038 ClipMode::ClipOut => ClipMode::Clip,
2039 }
2040 }
2041}
2042
2043#[repr(C)]
2044#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
2045pub struct ComplexClipRegion {
2046 pub rect: LayoutRect,
2048 pub radii: BorderRadius,
2050 pub mode: ClipMode,
2053}
2054
2055impl BorderRadius {
2056 pub fn zero() -> BorderRadius {
2057 BorderRadius {
2058 top_left: LayoutSize::new(0.0, 0.0),
2059 top_right: LayoutSize::new(0.0, 0.0),
2060 bottom_left: LayoutSize::new(0.0, 0.0),
2061 bottom_right: LayoutSize::new(0.0, 0.0),
2062 }
2063 }
2064
2065 pub fn uniform(radius: f32) -> BorderRadius {
2066 BorderRadius {
2067 top_left: LayoutSize::new(radius, radius),
2068 top_right: LayoutSize::new(radius, radius),
2069 bottom_left: LayoutSize::new(radius, radius),
2070 bottom_right: LayoutSize::new(radius, radius),
2071 }
2072 }
2073
2074 pub fn uniform_size(radius: LayoutSize) -> BorderRadius {
2075 BorderRadius {
2076 top_left: radius,
2077 top_right: radius,
2078 bottom_left: radius,
2079 bottom_right: radius,
2080 }
2081 }
2082
2083 pub fn all_sides_uniform(&self) -> bool {
2084 let corner_is_uniform = |corner: &LayoutSize| corner.width == corner.height;
2085 corner_is_uniform(&self.top_left) &&
2086 corner_is_uniform(&self.top_right) &&
2087 corner_is_uniform(&self.bottom_right) &&
2088 corner_is_uniform(&self.bottom_left)
2089 }
2090
2091 pub fn can_use_fast_path_in(&self, rect: &LayoutRect) -> bool {
2092 if !self.all_sides_uniform() {
2093 return false;
2095 }
2096 let tl = self.top_left.width;
2101 if tl == self.bottom_right.width && tl == self.top_right.width && tl == self.bottom_left.width {
2102 return true;
2103 }
2104 let half_size = rect.size() * 0.5;
2105 let fits = |v: f32| v <= half_size.width && v <= half_size.height;
2106 fits(tl) && fits(self.bottom_right.width) && fits(self.top_right.width) && fits(self.bottom_left.width)
2107 }
2108
2109 pub fn is_zero(&self) -> bool {
2112 let corner_is_zero = |corner: &LayoutSize| corner.width == 0.0 || corner.height == 0.0;
2113 corner_is_zero(&self.top_left) &&
2114 corner_is_zero(&self.top_right) &&
2115 corner_is_zero(&self.bottom_right) &&
2116 corner_is_zero(&self.bottom_left)
2117 }
2118}
2119
2120impl ComplexClipRegion {
2121 pub fn new(
2123 rect: LayoutRect,
2124 radii: BorderRadius,
2125 mode: ClipMode,
2126 ) -> Self {
2127 ComplexClipRegion { rect, radii, mode }
2128 }
2129}
2130
2131impl ComplexClipRegion {
2132 pub fn get_local_clip_rect(&self) -> Option<LayoutRect> {
2134 match self.mode {
2135 ClipMode::Clip => {
2136 Some(self.rect)
2137 }
2138 ClipMode::ClipOut => {
2139 None
2140 }
2141 }
2142 }
2143}
2144
2145pub const POLYGON_CLIP_VERTEX_MAX: usize = 32;
2146
2147#[repr(u8)]
2148#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)]
2149pub enum FillRule {
2150 Nonzero = 0x1, Evenodd = 0x2, }
2153
2154impl From<u8> for FillRule {
2155 fn from(fill_rule: u8) -> Self {
2156 match fill_rule {
2157 0x1 => FillRule::Nonzero,
2158 0x2 => FillRule::Evenodd,
2159 _ => panic!("Unexpected FillRule value."),
2160 }
2161 }
2162}
2163
2164impl From<FillRule> for u8 {
2165 fn from(fill_rule: FillRule) -> Self {
2166 match fill_rule {
2167 FillRule::Nonzero => 0x1,
2168 FillRule::Evenodd => 0x2,
2169 }
2170 }
2171}
2172
2173#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
2174pub struct ClipChainId(pub u64, pub PipelineId);
2175
2176impl ClipChainId {
2177 pub const INVALID: Self = ClipChainId(!0, PipelineId::INVALID);
2178}
2179
2180#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
2182pub struct ClipId(pub usize, pub PipelineId);
2183
2184impl Default for ClipId {
2185 fn default() -> Self {
2186 ClipId::invalid()
2187 }
2188}
2189
2190const ROOT_CLIP_ID: usize = 0;
2191
2192impl ClipId {
2193 pub fn root(pipeline_id: PipelineId) -> Self {
2195 ClipId(ROOT_CLIP_ID, pipeline_id)
2196 }
2197
2198 pub fn invalid() -> Self {
2201 ClipId(!0, PipelineId::dummy())
2202 }
2203
2204 pub fn pipeline_id(&self) -> PipelineId {
2205 match *self {
2206 ClipId(_, pipeline_id) => pipeline_id,
2207 }
2208 }
2209
2210 pub fn is_root(&self) -> bool {
2211 match *self {
2212 ClipId(id, _) => id == ROOT_CLIP_ID,
2213 }
2214 }
2215
2216 pub fn is_valid(&self) -> bool {
2217 match *self {
2218 ClipId(id, _) => id != !0,
2219 }
2220 }
2221}
2222
2223#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
2225pub struct SpatialId(pub usize, PipelineId);
2226
2227const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0;
2228const ROOT_SCROLL_NODE_SPATIAL_ID: usize = 1;
2229
2230impl SpatialId {
2231 pub fn new(spatial_node_index: usize, pipeline_id: PipelineId) -> Self {
2232 SpatialId(spatial_node_index, pipeline_id)
2233 }
2234
2235 pub fn root_reference_frame(pipeline_id: PipelineId) -> Self {
2236 SpatialId(ROOT_REFERENCE_FRAME_SPATIAL_ID, pipeline_id)
2237 }
2238
2239 pub fn root_scroll_node(pipeline_id: PipelineId) -> Self {
2240 SpatialId(ROOT_SCROLL_NODE_SPATIAL_ID, pipeline_id)
2241 }
2242
2243 pub fn pipeline_id(&self) -> PipelineId {
2244 self.1
2245 }
2246}
2247
2248#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
2256#[repr(C)]
2257pub struct ExternalScrollId(pub u64, pub PipelineId);
2258
2259impl ExternalScrollId {
2260 pub fn pipeline_id(&self) -> PipelineId {
2261 self.1
2262 }
2263
2264 pub fn is_root(&self) -> bool {
2265 self.0 == 0
2266 }
2267}
2268
2269impl DisplayItem {
2270 pub fn debug_name(&self) -> &'static str {
2271 match *self {
2272 DisplayItem::Border(..) => "border",
2273 DisplayItem::BoxShadow(..) => "box_shadow",
2274 DisplayItem::ClearRectangle(..) => "clear_rectangle",
2275 DisplayItem::HitTest(..) => "hit_test",
2276 DisplayItem::RectClip(..) => "rect_clip",
2277 DisplayItem::RoundedRectClip(..) => "rounded_rect_clip",
2278 DisplayItem::ImageMaskClip(..) => "image_mask_clip",
2279 DisplayItem::ClipChain(..) => "clip_chain",
2280 DisplayItem::ConicGradient(..) => "conic_gradient",
2281 DisplayItem::Gradient(..) => "gradient",
2282 DisplayItem::Iframe(..) => "iframe",
2283 DisplayItem::Image(..) => "image",
2284 DisplayItem::RepeatingImage(..) => "repeating_image",
2285 DisplayItem::Line(..) => "line",
2286 DisplayItem::PopAllShadows => "pop_all_shadows",
2287 DisplayItem::PopReferenceFrame => "pop_reference_frame",
2288 DisplayItem::PopStackingContext => "pop_stacking_context",
2289 DisplayItem::PushShadow(..) => "push_shadow",
2290 DisplayItem::PushReferenceFrame(..) => "push_reference_frame",
2291 DisplayItem::PushStackingContext(..) => "push_stacking_context",
2292 DisplayItem::SetFilterOps => "set_filter_ops",
2293 DisplayItem::SetFilterData => "set_filter_data",
2294 DisplayItem::SetFilterPrimitives => "set_filter_primitives",
2295 DisplayItem::SetPoints => "set_points",
2296 DisplayItem::RadialGradient(..) => "radial_gradient",
2297 DisplayItem::Rectangle(..) => "rectangle",
2298 DisplayItem::SetGradientStops => "set_gradient_stops",
2299 DisplayItem::ReuseItems(..) => "reuse_item",
2300 DisplayItem::RetainedItems(..) => "retained_items",
2301 DisplayItem::Text(..) => "text",
2302 DisplayItem::YuvImage(..) => "yuv_image",
2303 DisplayItem::BackdropFilter(..) => "backdrop_filter",
2304 DisplayItem::DebugMarker(..) => "debug",
2305 }
2306 }
2307}
2308
2309macro_rules! impl_default_for_enums {
2310 ($($enum:ident => $init:expr ),+) => {
2311 $(impl Default for $enum {
2312 #[allow(unused_imports)]
2313 fn default() -> Self {
2314 use $enum::*;
2315 $init
2316 }
2317 })*
2318 }
2319}
2320
2321impl_default_for_enums! {
2322 DisplayItem => PopStackingContext,
2323 LineOrientation => Vertical,
2324 LineStyle => Solid,
2325 RepeatMode => Stretch,
2326 NinePatchBorderSource => Image(ImageKey::default(), ImageRendering::Auto),
2327 BorderDetails => Normal(NormalBorder::default()),
2328 BorderRadiusKind => Uniform,
2329 BorderStyle => None,
2330 BoxShadowClipMode => Outset,
2331 ExtendMode => Clamp,
2332 FilterOp => Identity,
2333 ComponentTransferFuncType => Identity,
2334 ClipMode => Clip,
2335 FillRule => Nonzero,
2336 ReferenceFrameKind => Transform {
2337 is_2d_scale_translation: false,
2338 should_snap: false,
2339 paired_with_perspective: false,
2340 },
2341 Rotation => Degree0,
2342 TransformStyle => Flat,
2343 RasterSpace => Local(f32::default()),
2344 MixBlendMode => Normal,
2345 ImageRendering => Auto,
2346 AlphaType => Alpha,
2347 YuvColorSpace => Rec601,
2348 YuvRangedColorSpace => Rec601Narrow,
2349 ColorRange => Limited,
2350 YuvData => NV12(ImageKey::default(), ImageKey::default()),
2351 YuvFormat => NV12,
2352 FilterPrimitiveInput => Original,
2353 ColorSpace => Srgb,
2354 CompositeOperator => Over
2355}