1use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero};
9use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
10use crate::values::generics::border::GenericBorderRadius;
11use crate::values::generics::position::GenericPositionOrAuto;
12use crate::values::generics::rect::Rect;
13use crate::values::specified::svg_path::{PathCommand, SVGPathData};
14use crate::Zero;
15use std::fmt::{self, Write};
16use style_traits::{CssWriter, ToCss};
17
18#[allow(missing_docs)]
20#[derive(
21    Animate,
22    Clone,
23    ComputeSquaredDistance,
24    Copy,
25    Debug,
26    MallocSizeOf,
27    PartialEq,
28    Parse,
29    SpecifiedValueInfo,
30    ToAnimatedValue,
31    ToComputedValue,
32    ToCss,
33    ToResolvedValue,
34    ToShmem,
35)]
36#[repr(u8)]
37pub enum ShapeGeometryBox {
38    #[css(skip)]
45    ElementDependent,
46    FillBox,
47    StrokeBox,
48    ViewBox,
49    ShapeBox(ShapeBox),
50}
51
52impl Default for ShapeGeometryBox {
53    fn default() -> Self {
54        Self::ElementDependent
55    }
56}
57
58#[inline]
60fn is_default_box_for_clip_path(b: &ShapeGeometryBox) -> bool {
61    matches!(b, ShapeGeometryBox::ElementDependent)
64        || matches!(b, ShapeGeometryBox::ShapeBox(ShapeBox::BorderBox))
65}
66
67#[allow(missing_docs)]
69#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
70#[derive(
71    Animate,
72    Clone,
73    Copy,
74    ComputeSquaredDistance,
75    Debug,
76    Eq,
77    MallocSizeOf,
78    Parse,
79    PartialEq,
80    SpecifiedValueInfo,
81    ToAnimatedValue,
82    ToComputedValue,
83    ToCss,
84    ToResolvedValue,
85    ToShmem,
86)]
87#[repr(u8)]
88pub enum ShapeBox {
89    MarginBox,
90    BorderBox,
91    PaddingBox,
92    ContentBox,
93}
94
95impl Default for ShapeBox {
96    fn default() -> Self {
97        ShapeBox::MarginBox
98    }
99}
100
101#[allow(missing_docs)]
103#[derive(
104    Animate,
105    Clone,
106    ComputeSquaredDistance,
107    Debug,
108    MallocSizeOf,
109    PartialEq,
110    SpecifiedValueInfo,
111    ToAnimatedValue,
112    ToComputedValue,
113    ToCss,
114    ToResolvedValue,
115    ToShmem,
116    ToTyped,
117)]
118#[animation(no_bound(U))]
119#[repr(u8)]
120pub enum GenericClipPath<BasicShape, U> {
121    #[animation(error)]
122    None,
123    #[animation(error)]
124    Url(U),
125    Shape(
126        Box<BasicShape>,
127        #[css(skip_if = "is_default_box_for_clip_path")] ShapeGeometryBox,
128    ),
129    #[animation(error)]
130    Box(ShapeGeometryBox),
131}
132
133pub use self::GenericClipPath as ClipPath;
134
135#[allow(missing_docs)]
137#[derive(
138    Animate,
139    Clone,
140    ComputeSquaredDistance,
141    Debug,
142    MallocSizeOf,
143    PartialEq,
144    SpecifiedValueInfo,
145    ToAnimatedValue,
146    ToComputedValue,
147    ToCss,
148    ToResolvedValue,
149    ToShmem,
150    ToTyped,
151)]
152#[animation(no_bound(I))]
153#[repr(u8)]
154pub enum GenericShapeOutside<BasicShape, I> {
155    #[animation(error)]
156    None,
157    #[animation(error)]
158    Image(I),
159    Shape(Box<BasicShape>, #[css(skip_if = "is_default")] ShapeBox),
160    #[animation(error)]
161    Box(ShapeBox),
162}
163
164pub use self::GenericShapeOutside as ShapeOutside;
165
166#[derive(
170    Animate,
171    Clone,
172    ComputeSquaredDistance,
173    Debug,
174    Deserialize,
175    MallocSizeOf,
176    PartialEq,
177    Serialize,
178    SpecifiedValueInfo,
179    ToAnimatedValue,
180    ToComputedValue,
181    ToCss,
182    ToResolvedValue,
183    ToShmem,
184)]
185#[repr(C, u8)]
186pub enum GenericBasicShape<
187    Angle,
188    Position,
189    LengthPercentage,
190    NonNegativeLengthPercentage,
191    BasicShapeRect,
192> {
193    Rect(BasicShapeRect),
195    Circle(
197        #[css(field_bound)]
198        #[shmem(field_bound)]
199        Circle<Position, NonNegativeLengthPercentage>,
200    ),
201    Ellipse(
203        #[css(field_bound)]
204        #[shmem(field_bound)]
205        Ellipse<Position, NonNegativeLengthPercentage>,
206    ),
207    Polygon(GenericPolygon<LengthPercentage>),
209    PathOrShape(
211        #[animation(field_bound)]
212        #[css(field_bound)]
213        GenericPathOrShapeFunction<Angle, LengthPercentage>,
214    ),
215}
216
217pub use self::GenericBasicShape as BasicShape;
218
219#[allow(missing_docs)]
221#[derive(
222    Animate,
223    Clone,
224    ComputeSquaredDistance,
225    Debug,
226    Deserialize,
227    MallocSizeOf,
228    PartialEq,
229    Serialize,
230    SpecifiedValueInfo,
231    ToAnimatedValue,
232    ToComputedValue,
233    ToResolvedValue,
234    ToShmem,
235)]
236#[css(function = "inset")]
237#[repr(C)]
238pub struct GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage> {
239    pub rect: Rect<LengthPercentage>,
240    #[shmem(field_bound)]
241    pub round: GenericBorderRadius<NonNegativeLengthPercentage>,
242}
243
244pub use self::GenericInsetRect as InsetRect;
245
246#[allow(missing_docs)]
248#[derive(
249    Animate,
250    Clone,
251    ComputeSquaredDistance,
252    Copy,
253    Debug,
254    Deserialize,
255    MallocSizeOf,
256    PartialEq,
257    Serialize,
258    SpecifiedValueInfo,
259    ToAnimatedValue,
260    ToComputedValue,
261    ToResolvedValue,
262    ToShmem,
263)]
264#[css(function)]
265#[repr(C)]
266pub struct Circle<Position, NonNegativeLengthPercentage> {
267    pub position: GenericPositionOrAuto<Position>,
268    pub radius: GenericShapeRadius<NonNegativeLengthPercentage>,
269}
270
271#[allow(missing_docs)]
273#[derive(
274    Animate,
275    Clone,
276    ComputeSquaredDistance,
277    Copy,
278    Debug,
279    Deserialize,
280    MallocSizeOf,
281    PartialEq,
282    Serialize,
283    SpecifiedValueInfo,
284    ToAnimatedValue,
285    ToComputedValue,
286    ToResolvedValue,
287    ToShmem,
288)]
289#[css(function)]
290#[repr(C)]
291pub struct Ellipse<Position, NonNegativeLengthPercentage> {
292    pub position: GenericPositionOrAuto<Position>,
293    pub semiaxis_x: GenericShapeRadius<NonNegativeLengthPercentage>,
294    pub semiaxis_y: GenericShapeRadius<NonNegativeLengthPercentage>,
295}
296
297#[allow(missing_docs)]
299#[derive(
300    Animate,
301    Clone,
302    ComputeSquaredDistance,
303    Copy,
304    Debug,
305    Deserialize,
306    MallocSizeOf,
307    Parse,
308    PartialEq,
309    Serialize,
310    SpecifiedValueInfo,
311    ToAnimatedValue,
312    ToComputedValue,
313    ToCss,
314    ToResolvedValue,
315    ToShmem,
316)]
317#[repr(C, u8)]
318pub enum GenericShapeRadius<NonNegativeLengthPercentage> {
319    Length(NonNegativeLengthPercentage),
320    #[animation(error)]
321    ClosestSide,
322    #[animation(error)]
323    FarthestSide,
324}
325
326pub use self::GenericShapeRadius as ShapeRadius;
327
328#[derive(
332    Clone,
333    Debug,
334    Deserialize,
335    MallocSizeOf,
336    PartialEq,
337    Serialize,
338    SpecifiedValueInfo,
339    ToAnimatedValue,
340    ToComputedValue,
341    ToCss,
342    ToResolvedValue,
343    ToShmem,
344)]
345#[css(comma, function = "polygon")]
346#[repr(C)]
347pub struct GenericPolygon<LengthPercentage> {
348    #[css(skip_if = "is_default")]
350    pub fill: FillRule,
351    #[css(iterable)]
353    pub coordinates: crate::OwnedSlice<PolygonCoord<LengthPercentage>>,
354}
355
356pub use self::GenericPolygon as Polygon;
357
358#[derive(
360    Animate,
361    Clone,
362    ComputeSquaredDistance,
363    Debug,
364    Deserialize,
365    MallocSizeOf,
366    PartialEq,
367    Serialize,
368    SpecifiedValueInfo,
369    ToAnimatedValue,
370    ToComputedValue,
371    ToCss,
372    ToResolvedValue,
373    ToShmem,
374)]
375#[repr(C)]
376pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercentage);
377
378#[derive(
380    Clone,
381    ComputeSquaredDistance,
382    Debug,
383    Deserialize,
384    MallocSizeOf,
385    PartialEq,
386    Serialize,
387    SpecifiedValueInfo,
388    ToAnimatedValue,
389    ToComputedValue,
390    ToCss,
391    ToResolvedValue,
392    ToShmem,
393)]
394#[repr(C, u8)]
395pub enum GenericPathOrShapeFunction<Angle, LengthPercentage> {
396    Path(Path),
398    Shape(#[css(field_bound)] Shape<Angle, LengthPercentage>),
400}
401
402#[allow(missing_docs)]
407#[derive(
408    Animate,
409    Clone,
410    ComputeSquaredDistance,
411    Copy,
412    Debug,
413    Deserialize,
414    Eq,
415    MallocSizeOf,
416    Parse,
417    PartialEq,
418    Serialize,
419    SpecifiedValueInfo,
420    ToAnimatedValue,
421    ToComputedValue,
422    ToCss,
423    ToResolvedValue,
424    ToShmem,
425    ToTyped,
426)]
427#[repr(u8)]
428pub enum FillRule {
429    Nonzero,
430    Evenodd,
431}
432
433#[derive(
437    Animate,
438    Clone,
439    ComputeSquaredDistance,
440    Debug,
441    Deserialize,
442    MallocSizeOf,
443    PartialEq,
444    Serialize,
445    SpecifiedValueInfo,
446    ToAnimatedValue,
447    ToComputedValue,
448    ToCss,
449    ToResolvedValue,
450    ToShmem,
451)]
452#[css(comma, function = "path")]
453#[repr(C)]
454pub struct Path {
455    #[css(skip_if = "is_default")]
457    pub fill: FillRule,
458    pub path: SVGPathData,
460}
461
462impl Path {
463    #[inline]
465    pub fn commands(&self) -> &[PathCommand] {
466        self.path.commands()
467    }
468}
469
470impl<B, U> ToAnimatedZero for ClipPath<B, U> {
471    fn to_animated_zero(&self) -> Result<Self, ()> {
472        Err(())
473    }
474}
475
476impl<B, U> ToAnimatedZero for ShapeOutside<B, U> {
477    fn to_animated_zero(&self) -> Result<Self, ()> {
478        Err(())
479    }
480}
481
482impl<Length, NonNegativeLength> ToCss for InsetRect<Length, NonNegativeLength>
483where
484    Length: ToCss + PartialEq,
485    NonNegativeLength: ToCss + PartialEq + Zero,
486{
487    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
488    where
489        W: Write,
490    {
491        dest.write_str("inset(")?;
492        self.rect.to_css(dest)?;
493        if !self.round.is_zero() {
494            dest.write_str(" round ")?;
495            self.round.to_css(dest)?;
496        }
497        dest.write_char(')')
498    }
499}
500
501impl<Position, NonNegativeLengthPercentage> ToCss for Circle<Position, NonNegativeLengthPercentage>
502where
503    Position: ToCss,
504    NonNegativeLengthPercentage: ToCss + PartialEq,
505{
506    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
507    where
508        W: Write,
509    {
510        let has_radius = self.radius != Default::default();
511
512        dest.write_str("circle(")?;
513        if has_radius {
514            self.radius.to_css(dest)?;
515        }
516
517        if !matches!(self.position, GenericPositionOrAuto::Auto) {
520            if has_radius {
521                dest.write_char(' ')?;
522            }
523            dest.write_str("at ")?;
524            self.position.to_css(dest)?;
525        }
526        dest.write_char(')')
527    }
528}
529
530impl<Position, NonNegativeLengthPercentage> ToCss for Ellipse<Position, NonNegativeLengthPercentage>
531where
532    Position: ToCss,
533    NonNegativeLengthPercentage: ToCss + PartialEq,
534{
535    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
536    where
537        W: Write,
538    {
539        let has_radii =
540            self.semiaxis_x != Default::default() || self.semiaxis_y != Default::default();
541
542        dest.write_str("ellipse(")?;
543        if has_radii {
544            self.semiaxis_x.to_css(dest)?;
545            dest.write_char(' ')?;
546            self.semiaxis_y.to_css(dest)?;
547        }
548
549        if !matches!(self.position, GenericPositionOrAuto::Auto) {
552            if has_radii {
553                dest.write_char(' ')?;
554            }
555            dest.write_str("at ")?;
556            self.position.to_css(dest)?;
557        }
558        dest.write_char(')')
559    }
560}
561
562impl<L> Default for ShapeRadius<L> {
563    #[inline]
564    fn default() -> Self {
565        ShapeRadius::ClosestSide
566    }
567}
568
569impl<L> Animate for Polygon<L>
570where
571    L: Animate,
572{
573    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
574        if self.fill != other.fill {
575            return Err(());
576        }
577        let coordinates =
578            lists::by_computed_value::animate(&self.coordinates, &other.coordinates, procedure)?;
579        Ok(Polygon {
580            fill: self.fill,
581            coordinates,
582        })
583    }
584}
585
586impl<L> ComputeSquaredDistance for Polygon<L>
587where
588    L: ComputeSquaredDistance,
589{
590    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
591        if self.fill != other.fill {
592            return Err(());
593        }
594        lists::by_computed_value::squared_distance(&self.coordinates, &other.coordinates)
595    }
596}
597
598impl Default for FillRule {
599    #[inline]
600    fn default() -> Self {
601        FillRule::Nonzero
602    }
603}
604
605#[inline]
606fn is_default<T: Default + PartialEq>(fill: &T) -> bool {
607    *fill == Default::default()
608}
609
610#[derive(
615    Clone,
616    Debug,
617    Deserialize,
618    MallocSizeOf,
619    PartialEq,
620    Serialize,
621    SpecifiedValueInfo,
622    ToAnimatedValue,
623    ToComputedValue,
624    ToResolvedValue,
625    ToShmem,
626)]
627#[repr(C)]
628pub struct Shape<Angle, LengthPercentage> {
629    pub fill: FillRule,
631    pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, LengthPercentage>>,
635}
636
637impl<Angle, LengthPercentage> Shape<Angle, LengthPercentage> {
638    #[inline]
640    pub fn commands(&self) -> &[GenericShapeCommand<Angle, LengthPercentage>] {
641        &self.commands
642    }
643}
644
645impl<Angle, LengthPercentage> Animate for Shape<Angle, LengthPercentage>
646where
647    Angle: Animate,
648    LengthPercentage: Animate,
649{
650    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
651        if self.fill != other.fill {
652            return Err(());
653        }
654        let commands =
655            lists::by_computed_value::animate(&self.commands, &other.commands, procedure)?;
656        Ok(Self {
657            fill: self.fill,
658            commands,
659        })
660    }
661}
662
663impl<Angle, LengthPercentage> ComputeSquaredDistance for Shape<Angle, LengthPercentage>
664where
665    Angle: ComputeSquaredDistance,
666    LengthPercentage: ComputeSquaredDistance,
667{
668    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
669        if self.fill != other.fill {
670            return Err(());
671        }
672        lists::by_computed_value::squared_distance(&self.commands, &other.commands)
673    }
674}
675
676impl<Angle, LengthPercentage> ToCss for Shape<Angle, LengthPercentage>
677where
678    Angle: ToCss + Zero,
679    LengthPercentage: PartialEq + ToCss,
680{
681    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
682    where
683        W: Write,
684    {
685        use style_traits::values::SequenceWriter;
686
687        debug_assert!(self.commands.len() > 1);
689
690        dest.write_str("shape(")?;
691        if !is_default(&self.fill) {
692            self.fill.to_css(dest)?;
693            dest.write_char(' ')?;
694        }
695        dest.write_str("from ")?;
696        match self.commands[0] {
697            ShapeCommand::Move {
698                by_to: _,
699                ref point,
700            } => point.to_css(dest)?,
701            _ => unreachable!("The first command must be move"),
702        }
703        dest.write_str(", ")?;
704        {
705            let mut writer = SequenceWriter::new(dest, ", ");
706            for command in self.commands.iter().skip(1) {
707                writer.item(command)?;
708            }
709        }
710        dest.write_char(')')
711    }
712}
713
714#[derive(
719    Animate,
720    Clone,
721    ComputeSquaredDistance,
722    Copy,
723    Debug,
724    Deserialize,
725    MallocSizeOf,
726    PartialEq,
727    Serialize,
728    SpecifiedValueInfo,
729    ToAnimatedValue,
730    ToAnimatedZero,
731    ToComputedValue,
732    ToResolvedValue,
733    ToShmem,
734)]
735#[allow(missing_docs)]
736#[repr(C, u8)]
737pub enum GenericShapeCommand<Angle, LengthPercentage> {
738    Move {
740        by_to: ByTo,
741        point: CoordinatePair<LengthPercentage>,
742    },
743    Line {
745        by_to: ByTo,
746        point: CoordinatePair<LengthPercentage>,
747    },
748    HLine { by_to: ByTo, x: LengthPercentage },
750    VLine { by_to: ByTo, y: LengthPercentage },
752    CubicCurve {
754        by_to: ByTo,
755        point: CoordinatePair<LengthPercentage>,
756        control1: CoordinatePair<LengthPercentage>,
757        control2: CoordinatePair<LengthPercentage>,
758    },
759    QuadCurve {
761        by_to: ByTo,
762        point: CoordinatePair<LengthPercentage>,
763        control1: CoordinatePair<LengthPercentage>,
764    },
765    SmoothCubic {
767        by_to: ByTo,
768        point: CoordinatePair<LengthPercentage>,
769        control2: CoordinatePair<LengthPercentage>,
770    },
771    SmoothQuad {
773        by_to: ByTo,
774        point: CoordinatePair<LengthPercentage>,
775    },
776    Arc {
778        by_to: ByTo,
779        point: CoordinatePair<LengthPercentage>,
780        radii: CoordinatePair<LengthPercentage>,
781        arc_sweep: ArcSweep,
782        arc_size: ArcSize,
783        rotate: Angle,
784    },
785    Close,
787}
788
789pub use self::GenericShapeCommand as ShapeCommand;
790
791impl<Angle, LengthPercentage> ToCss for ShapeCommand<Angle, LengthPercentage>
792where
793    Angle: ToCss + Zero,
794    LengthPercentage: PartialEq + ToCss,
795{
796    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
797    where
798        W: fmt::Write,
799    {
800        use self::ShapeCommand::*;
801        match *self {
802            Move { by_to, ref point } => {
803                dest.write_str("move ")?;
804                by_to.to_css(dest)?;
805                dest.write_char(' ')?;
806                point.to_css(dest)
807            },
808            Line { by_to, ref point } => {
809                dest.write_str("line ")?;
810                by_to.to_css(dest)?;
811                dest.write_char(' ')?;
812                point.to_css(dest)
813            },
814            HLine { by_to, ref x } => {
815                dest.write_str("hline ")?;
816                by_to.to_css(dest)?;
817                dest.write_char(' ')?;
818                x.to_css(dest)
819            },
820            VLine { by_to, ref y } => {
821                dest.write_str("vline ")?;
822                by_to.to_css(dest)?;
823                dest.write_char(' ')?;
824                y.to_css(dest)
825            },
826            CubicCurve {
827                by_to,
828                ref point,
829                ref control1,
830                ref control2,
831            } => {
832                dest.write_str("curve ")?;
833                by_to.to_css(dest)?;
834                dest.write_char(' ')?;
835                point.to_css(dest)?;
836                dest.write_str(" via ")?;
837                control1.to_css(dest)?;
838                dest.write_char(' ')?;
839                control2.to_css(dest)
840            },
841            QuadCurve {
842                by_to,
843                ref point,
844                ref control1,
845            } => {
846                dest.write_str("curve ")?;
847                by_to.to_css(dest)?;
848                dest.write_char(' ')?;
849                point.to_css(dest)?;
850                dest.write_str(" via ")?;
851                control1.to_css(dest)
852            },
853            SmoothCubic {
854                by_to,
855                ref point,
856                ref control2,
857            } => {
858                dest.write_str("smooth ")?;
859                by_to.to_css(dest)?;
860                dest.write_char(' ')?;
861                point.to_css(dest)?;
862                dest.write_str(" via ")?;
863                control2.to_css(dest)
864            },
865            SmoothQuad { by_to, ref point } => {
866                dest.write_str("smooth ")?;
867                by_to.to_css(dest)?;
868                dest.write_char(' ')?;
869                point.to_css(dest)
870            },
871            Arc {
872                by_to,
873                ref point,
874                ref radii,
875                arc_sweep,
876                arc_size,
877                ref rotate,
878            } => {
879                dest.write_str("arc ")?;
880                by_to.to_css(dest)?;
881                dest.write_char(' ')?;
882                point.to_css(dest)?;
883                dest.write_str(" of ")?;
884                radii.x.to_css(dest)?;
885                if radii.x != radii.y {
886                    dest.write_char(' ')?;
887                    radii.y.to_css(dest)?;
888                }
889
890                if matches!(arc_sweep, ArcSweep::Cw) {
891                    dest.write_str(" cw")?;
892                }
893
894                if matches!(arc_size, ArcSize::Large) {
895                    dest.write_str(" large")?;
896                }
897
898                if !rotate.is_zero() {
899                    dest.write_str(" rotate ")?;
900                    rotate.to_css(dest)?;
901                }
902                Ok(())
903            },
904            Close => dest.write_str("close"),
905        }
906    }
907}
908
909#[derive(
912    Animate,
913    Clone,
914    ComputeSquaredDistance,
915    Copy,
916    Debug,
917    Deserialize,
918    MallocSizeOf,
919    Parse,
920    PartialEq,
921    Serialize,
922    SpecifiedValueInfo,
923    ToAnimatedValue,
924    ToAnimatedZero,
925    ToComputedValue,
926    ToCss,
927    ToResolvedValue,
928    ToShmem,
929)]
930#[repr(u8)]
931pub enum ByTo {
932    By,
934    To,
936}
937
938impl ByTo {
939    #[inline]
941    pub fn is_abs(&self) -> bool {
942        matches!(self, ByTo::To)
943    }
944
945    #[inline]
947    pub fn new(is_abs: bool) -> Self {
948        if is_abs {
949            Self::To
950        } else {
951            Self::By
952        }
953    }
954}
955
956#[allow(missing_docs)]
961#[derive(
962    AddAssign,
963    Animate,
964    Clone,
965    ComputeSquaredDistance,
966    Copy,
967    Debug,
968    Deserialize,
969    MallocSizeOf,
970    PartialEq,
971    Serialize,
972    SpecifiedValueInfo,
973    ToAnimatedValue,
974    ToAnimatedZero,
975    ToComputedValue,
976    ToCss,
977    ToResolvedValue,
978    ToShmem,
979)]
980#[repr(C)]
981pub struct CoordinatePair<LengthPercentage> {
982    pub x: LengthPercentage,
983    pub y: LengthPercentage,
984}
985
986impl<LengthPercentage> CoordinatePair<LengthPercentage> {
987    #[inline]
989    pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self {
990        Self { x, y }
991    }
992}
993
994#[derive(
998    Clone,
999    Copy,
1000    Debug,
1001    Deserialize,
1002    FromPrimitive,
1003    MallocSizeOf,
1004    Parse,
1005    PartialEq,
1006    Serialize,
1007    SpecifiedValueInfo,
1008    ToAnimatedValue,
1009    ToAnimatedZero,
1010    ToComputedValue,
1011    ToCss,
1012    ToResolvedValue,
1013    ToShmem,
1014)]
1015#[repr(u8)]
1016pub enum ArcSweep {
1017    Ccw = 0,
1019    Cw = 1,
1021}
1022
1023impl Animate for ArcSweep {
1024    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1025        use num_traits::FromPrimitive;
1026        (*self as i32)
1029            .animate(&(*other as i32), procedure)
1030            .map(|v| ArcSweep::from_u8((v > 0) as u8).unwrap_or(ArcSweep::Ccw))
1031    }
1032}
1033
1034impl ComputeSquaredDistance for ArcSweep {
1035    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1036        (*self as i32).compute_squared_distance(&(*other as i32))
1037    }
1038}
1039
1040#[derive(
1044    Clone,
1045    Copy,
1046    Debug,
1047    Deserialize,
1048    FromPrimitive,
1049    MallocSizeOf,
1050    Parse,
1051    PartialEq,
1052    Serialize,
1053    SpecifiedValueInfo,
1054    ToAnimatedValue,
1055    ToAnimatedZero,
1056    ToComputedValue,
1057    ToCss,
1058    ToResolvedValue,
1059    ToShmem,
1060)]
1061#[repr(u8)]
1062pub enum ArcSize {
1063    Small = 0,
1065    Large = 1,
1067}
1068
1069impl Animate for ArcSize {
1070    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1071        use num_traits::FromPrimitive;
1072        (*self as i32)
1075            .animate(&(*other as i32), procedure)
1076            .map(|v| ArcSize::from_u8((v > 0) as u8).unwrap_or(ArcSize::Small))
1077    }
1078}
1079
1080impl ComputeSquaredDistance for ArcSize {
1081    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1082        (*self as i32).compute_squared_distance(&(*other as i32))
1083    }
1084}