1use crate::derives::*;
9use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero};
10use crate::values::computed::Percentage;
11use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
12use crate::values::generics::{
13 border::GenericBorderRadius, position::GenericPositionOrAuto, rect::Rect, NonNegative, Optional,
14};
15use crate::values::specified::svg_path::{PathCommand, SVGPathData};
16use crate::Zero;
17use std::fmt::{self, Write};
18use style_traits::{CssWriter, ToCss};
19
20#[allow(missing_docs)]
22#[derive(
23 Animate,
24 Clone,
25 ComputeSquaredDistance,
26 Copy,
27 Debug,
28 MallocSizeOf,
29 PartialEq,
30 Parse,
31 SpecifiedValueInfo,
32 ToAnimatedValue,
33 ToComputedValue,
34 ToCss,
35 ToResolvedValue,
36 ToShmem,
37 ToTyped,
38)]
39#[repr(u8)]
40pub enum ShapeGeometryBox {
41 #[css(skip)]
48 ElementDependent,
49 FillBox,
50 StrokeBox,
51 ViewBox,
52 ShapeBox(ShapeBox),
53}
54
55impl Default for ShapeGeometryBox {
56 fn default() -> Self {
57 Self::ElementDependent
58 }
59}
60
61#[inline]
63fn is_default_box_for_clip_path(b: &ShapeGeometryBox) -> bool {
64 matches!(b, ShapeGeometryBox::ElementDependent)
67 || matches!(b, ShapeGeometryBox::ShapeBox(ShapeBox::BorderBox))
68}
69
70#[allow(missing_docs)]
72#[derive(
73 Animate,
74 Clone,
75 Copy,
76 ComputeSquaredDistance,
77 Debug,
78 Deserialize,
79 Eq,
80 MallocSizeOf,
81 Parse,
82 PartialEq,
83 Serialize,
84 SpecifiedValueInfo,
85 ToAnimatedValue,
86 ToComputedValue,
87 ToCss,
88 ToResolvedValue,
89 ToShmem,
90 ToTyped,
91)]
92#[repr(u8)]
93pub enum ShapeBox {
94 MarginBox,
95 BorderBox,
96 PaddingBox,
97 ContentBox,
98}
99
100impl Default for ShapeBox {
101 fn default() -> Self {
102 ShapeBox::MarginBox
103 }
104}
105
106#[allow(missing_docs)]
108#[derive(
109 Animate,
110 Clone,
111 ComputeSquaredDistance,
112 Debug,
113 MallocSizeOf,
114 PartialEq,
115 SpecifiedValueInfo,
116 ToAnimatedValue,
117 ToComputedValue,
118 ToCss,
119 ToResolvedValue,
120 ToShmem,
121 ToTyped,
122)]
123#[animation(no_bound(U))]
124#[repr(u8)]
125pub enum GenericClipPath<BasicShape, U> {
126 #[animation(error)]
127 None,
128 #[animation(error)]
129 #[typed(todo)]
133 Url(U),
134 #[typed(skip)]
135 Shape(
136 #[animation(field_bound)] Box<BasicShape>,
137 #[css(skip_if = "is_default_box_for_clip_path")] ShapeGeometryBox,
138 ),
139 #[animation(error)]
140 Box(ShapeGeometryBox),
141}
142
143pub use self::GenericClipPath as ClipPath;
144
145#[allow(missing_docs)]
147#[derive(
148 Animate,
149 Clone,
150 ComputeSquaredDistance,
151 Debug,
152 MallocSizeOf,
153 PartialEq,
154 SpecifiedValueInfo,
155 ToAnimatedValue,
156 ToComputedValue,
157 ToCss,
158 ToResolvedValue,
159 ToShmem,
160 ToTyped,
161)]
162#[animation(no_bound(I))]
163#[repr(u8)]
164pub enum GenericShapeOutside<BasicShape, I> {
165 #[animation(error)]
166 None,
167 #[animation(error)]
168 Image(I),
169 #[typed(skip)]
170 Shape(Box<BasicShape>, #[css(skip_if = "is_default")] ShapeBox),
171 #[animation(error)]
172 Box(ShapeBox),
173}
174
175pub use self::GenericShapeOutside as ShapeOutside;
176
177#[derive(
181 Animate,
182 Clone,
183 ComputeSquaredDistance,
184 Debug,
185 Deserialize,
186 MallocSizeOf,
187 PartialEq,
188 Serialize,
189 SpecifiedValueInfo,
190 ToAnimatedValue,
191 ToComputedValue,
192 ToCss,
193 ToResolvedValue,
194 ToShmem,
195)]
196#[repr(C, u8)]
197pub enum GenericBasicShape<Angle, Position, LengthPercentage, BasicShapeRect> {
198 Rect(BasicShapeRect),
200 Circle(
202 #[animation(field_bound)]
203 #[css(field_bound)]
204 #[shmem(field_bound)]
205 Circle<Position, LengthPercentage>,
206 ),
207 Ellipse(
209 #[animation(field_bound)]
210 #[css(field_bound)]
211 #[shmem(field_bound)]
212 Ellipse<Position, LengthPercentage>,
213 ),
214 Polygon(GenericPolygon<LengthPercentage>),
216 PathOrShape(
218 #[animation(field_bound)]
219 #[css(field_bound)]
220 #[compute(field_bound)]
221 GenericPathOrShapeFunction<Angle, Position, LengthPercentage>,
222 ),
223}
224
225pub use self::GenericBasicShape as BasicShape;
226
227#[allow(missing_docs)]
229#[derive(
230 Animate,
231 Clone,
232 ComputeSquaredDistance,
233 Debug,
234 Deserialize,
235 MallocSizeOf,
236 PartialEq,
237 Serialize,
238 SpecifiedValueInfo,
239 ToAnimatedValue,
240 ToComputedValue,
241 ToResolvedValue,
242 ToShmem,
243)]
244#[css(function = "inset")]
245#[repr(C)]
246pub struct GenericInsetRect<LengthPercentage> {
247 pub rect: Rect<LengthPercentage>,
248 #[shmem(field_bound)]
249 #[animation(field_bound)]
250 pub round: GenericBorderRadius<NonNegative<LengthPercentage>>,
251}
252
253pub use self::GenericInsetRect as InsetRect;
254
255#[allow(missing_docs)]
257#[derive(
258 Animate,
259 Clone,
260 ComputeSquaredDistance,
261 Copy,
262 Debug,
263 Deserialize,
264 MallocSizeOf,
265 PartialEq,
266 Serialize,
267 SpecifiedValueInfo,
268 ToAnimatedValue,
269 ToComputedValue,
270 ToResolvedValue,
271 ToShmem,
272)]
273#[css(function)]
274#[repr(C)]
275pub struct Circle<Position, LengthPercentage> {
276 pub position: GenericPositionOrAuto<Position>,
277 #[animation(field_bound)]
278 pub radius: GenericShapeRadius<LengthPercentage>,
279}
280
281#[allow(missing_docs)]
283#[derive(
284 Animate,
285 Clone,
286 ComputeSquaredDistance,
287 Copy,
288 Debug,
289 Deserialize,
290 MallocSizeOf,
291 PartialEq,
292 Serialize,
293 SpecifiedValueInfo,
294 ToAnimatedValue,
295 ToComputedValue,
296 ToResolvedValue,
297 ToShmem,
298)]
299#[css(function)]
300#[repr(C)]
301pub struct Ellipse<Position, LengthPercentage> {
302 pub position: GenericPositionOrAuto<Position>,
303 #[animation(field_bound)]
304 pub semiaxis_x: GenericShapeRadius<LengthPercentage>,
305 #[animation(field_bound)]
306 pub semiaxis_y: GenericShapeRadius<LengthPercentage>,
307}
308
309#[allow(missing_docs)]
311#[derive(
312 Animate,
313 Clone,
314 ComputeSquaredDistance,
315 Copy,
316 Debug,
317 Deserialize,
318 MallocSizeOf,
319 Parse,
320 PartialEq,
321 Serialize,
322 SpecifiedValueInfo,
323 ToAnimatedValue,
324 ToComputedValue,
325 ToCss,
326 ToResolvedValue,
327 ToShmem,
328)]
329#[repr(C, u8)]
330pub enum GenericShapeRadius<LengthPercentage> {
331 Length(
332 #[animation(field_bound)]
333 #[parse(field_bound)]
334 NonNegative<LengthPercentage>,
335 ),
336 #[animation(error)]
337 ClosestSide,
338 #[animation(error)]
339 FarthestSide,
340 #[animation(error)]
341 FarthestCorner,
342 #[animation(error)]
343 ClosestCorner,
344}
345
346pub use self::GenericShapeRadius as ShapeRadius;
347
348#[derive(
352 Clone,
353 Debug,
354 Deserialize,
355 MallocSizeOf,
356 PartialEq,
357 Serialize,
358 SpecifiedValueInfo,
359 ToAnimatedValue,
360 ToComputedValue,
361 ToCss,
362 ToResolvedValue,
363 ToShmem,
364)]
365#[css(comma, function = "polygon")]
366#[repr(C)]
367pub struct GenericPolygon<LengthPercentage> {
368 #[css(skip_if = "is_default")]
370 pub fill: FillRule,
371 #[css(iterable)]
373 pub coordinates: crate::OwnedSlice<PolygonCoord<LengthPercentage>>,
374}
375
376pub use self::GenericPolygon as Polygon;
377
378#[derive(
380 Animate,
381 Clone,
382 ComputeSquaredDistance,
383 Debug,
384 Deserialize,
385 MallocSizeOf,
386 PartialEq,
387 Serialize,
388 SpecifiedValueInfo,
389 ToAnimatedValue,
390 ToComputedValue,
391 ToCss,
392 ToResolvedValue,
393 ToShmem,
394)]
395#[repr(C)]
396pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercentage);
397
398#[derive(
400 Clone,
401 ComputeSquaredDistance,
402 Debug,
403 Deserialize,
404 MallocSizeOf,
405 PartialEq,
406 Serialize,
407 SpecifiedValueInfo,
408 ToAnimatedValue,
409 ToComputedValue,
410 ToCss,
411 ToResolvedValue,
412 ToShmem,
413)]
414#[repr(C, u8)]
415pub enum GenericPathOrShapeFunction<Angle, Position, LengthPercentage> {
416 Path(Path),
418 Shape(
420 #[css(field_bound)]
421 #[compute(field_bound)]
422 Shape<Angle, Position, LengthPercentage>,
423 ),
424}
425
426#[allow(missing_docs)]
431#[derive(
432 Animate,
433 Clone,
434 ComputeSquaredDistance,
435 Copy,
436 Debug,
437 Deserialize,
438 Eq,
439 MallocSizeOf,
440 Parse,
441 PartialEq,
442 Serialize,
443 SpecifiedValueInfo,
444 ToAnimatedValue,
445 ToComputedValue,
446 ToCss,
447 ToResolvedValue,
448 ToShmem,
449 ToTyped,
450)]
451#[repr(u8)]
452pub enum FillRule {
453 Nonzero,
454 Evenodd,
455}
456
457#[derive(
461 Animate,
462 Clone,
463 ComputeSquaredDistance,
464 Debug,
465 Deserialize,
466 MallocSizeOf,
467 PartialEq,
468 Serialize,
469 SpecifiedValueInfo,
470 ToAnimatedValue,
471 ToComputedValue,
472 ToCss,
473 ToResolvedValue,
474 ToShmem,
475)]
476#[css(comma, function = "path")]
477#[repr(C)]
478pub struct Path {
479 #[css(skip_if = "is_default")]
481 pub fill: FillRule,
482 pub path: SVGPathData,
484}
485
486impl Path {
487 #[inline]
489 pub fn commands(&self) -> &[PathCommand] {
490 self.path.commands()
491 }
492}
493
494impl<B, U> ToAnimatedZero for ClipPath<B, U> {
495 fn to_animated_zero(&self) -> Result<Self, ()> {
496 Err(())
497 }
498}
499
500impl<B, U> ToAnimatedZero for ShapeOutside<B, U> {
501 fn to_animated_zero(&self) -> Result<Self, ()> {
502 Err(())
503 }
504}
505
506impl<Length> ToCss for InsetRect<Length>
507where
508 Length: ToCss + PartialEq + Zero,
509{
510 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
511 where
512 W: Write,
513 {
514 dest.write_str("inset(")?;
515 self.rect.to_css(dest)?;
516 if !self.round.is_zero() {
517 dest.write_str(" round ")?;
518 self.round.to_css(dest)?;
519 }
520 dest.write_char(')')
521 }
522}
523
524impl<Position, LengthPercentage> ToCss for Circle<Position, LengthPercentage>
525where
526 LengthPercentage: ToCss + PartialEq,
527 Position: ToCss,
528{
529 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
530 where
531 W: Write,
532 {
533 let has_radius = self.radius != Default::default();
534
535 dest.write_str("circle(")?;
536 if has_radius {
537 self.radius.to_css(dest)?;
538 }
539
540 if !matches!(self.position, GenericPositionOrAuto::Auto) {
543 if has_radius {
544 dest.write_char(' ')?;
545 }
546 dest.write_str("at ")?;
547 self.position.to_css(dest)?;
548 }
549 dest.write_char(')')
550 }
551}
552
553impl<Position, LengthPercentage> ToCss for Ellipse<Position, LengthPercentage>
554where
555 LengthPercentage: ToCss + PartialEq,
556 Position: ToCss,
557{
558 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
559 where
560 W: Write,
561 {
562 let has_radii =
563 self.semiaxis_x != Default::default() || self.semiaxis_y != Default::default();
564
565 dest.write_str("ellipse(")?;
566 if has_radii {
567 self.semiaxis_x.to_css(dest)?;
568 dest.write_char(' ')?;
569 self.semiaxis_y.to_css(dest)?;
570 }
571
572 if !matches!(self.position, GenericPositionOrAuto::Auto) {
575 if has_radii {
576 dest.write_char(' ')?;
577 }
578 dest.write_str("at ")?;
579 self.position.to_css(dest)?;
580 }
581 dest.write_char(')')
582 }
583}
584
585impl<L> Default for ShapeRadius<L> {
586 #[inline]
587 fn default() -> Self {
588 ShapeRadius::ClosestSide
589 }
590}
591
592impl<L> Animate for Polygon<L>
593where
594 L: Animate,
595{
596 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
597 if self.fill != other.fill {
598 return Err(());
599 }
600 let coordinates =
601 lists::by_computed_value::animate(&self.coordinates, &other.coordinates, procedure)?;
602 Ok(Polygon {
603 fill: self.fill,
604 coordinates,
605 })
606 }
607}
608
609impl<L> ComputeSquaredDistance for Polygon<L>
610where
611 L: ComputeSquaredDistance,
612{
613 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
614 if self.fill != other.fill {
615 return Err(());
616 }
617 lists::by_computed_value::squared_distance(&self.coordinates, &other.coordinates)
618 }
619}
620
621impl Default for FillRule {
622 #[inline]
623 fn default() -> Self {
624 FillRule::Nonzero
625 }
626}
627
628#[inline]
629fn is_default<T: Default + PartialEq>(fill: &T) -> bool {
630 *fill == Default::default()
631}
632
633#[derive(
638 Clone,
639 Debug,
640 Deserialize,
641 MallocSizeOf,
642 PartialEq,
643 Serialize,
644 SpecifiedValueInfo,
645 ToAnimatedValue,
646 ToComputedValue,
647 ToResolvedValue,
648 ToShmem,
649)]
650#[repr(C)]
651pub struct Shape<Angle, Position, LengthPercentage> {
652 pub fill: FillRule,
654 #[compute(field_bound)]
658 pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, Position, LengthPercentage>>,
659}
660
661impl<Angle, Position, LengthPercentage> Shape<Angle, Position, LengthPercentage> {
662 #[inline]
664 pub fn commands(&self) -> &[GenericShapeCommand<Angle, Position, LengthPercentage>] {
665 &self.commands
666 }
667}
668
669impl<Angle, Position, LengthPercentage> Animate for Shape<Angle, Position, LengthPercentage>
670where
671 Angle: Animate,
672 Position: Animate,
673 LengthPercentage: Animate,
674{
675 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
676 if self.fill != other.fill {
677 return Err(());
678 }
679 let commands =
680 lists::by_computed_value::animate(&self.commands, &other.commands, procedure)?;
681 Ok(Self {
682 fill: self.fill,
683 commands,
684 })
685 }
686}
687
688impl<Angle, Position, LengthPercentage> ComputeSquaredDistance
689 for Shape<Angle, Position, LengthPercentage>
690where
691 Angle: ComputeSquaredDistance,
692 Position: ComputeSquaredDistance,
693 LengthPercentage: ComputeSquaredDistance,
694{
695 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
696 if self.fill != other.fill {
697 return Err(());
698 }
699 lists::by_computed_value::squared_distance(&self.commands, &other.commands)
700 }
701}
702
703impl<Angle, Position, LengthPercentage> ToCss for Shape<Angle, Position, LengthPercentage>
704where
705 Angle: ToCss + Zero,
706 Position: ToCss,
707 LengthPercentage: PartialEq + ToCss,
708{
709 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
710 where
711 W: Write,
712 {
713 use style_traits::values::SequenceWriter;
714
715 debug_assert!(self.commands.len() > 1);
717
718 dest.write_str("shape(")?;
719 if !is_default(&self.fill) {
720 self.fill.to_css(dest)?;
721 dest.write_char(' ')?;
722 }
723 dest.write_str("from ")?;
724 match &self.commands[0] {
725 ShapeCommand::Move {
726 point: CommandEndPoint::ToPosition(pos),
727 } => pos.to_css(dest)?,
728 ShapeCommand::Move {
729 point: CommandEndPoint::ByCoordinate(coord),
730 } => coord.to_css(dest)?,
731 _ => unreachable!("The first command must be move"),
732 }
733 dest.write_str(", ")?;
734 {
735 let mut writer = SequenceWriter::new(dest, ", ");
736 for command in self.commands.iter().skip(1) {
737 writer.item(command)?;
738 }
739 }
740 dest.write_char(')')
741 }
742}
743
744#[derive(
749 Animate,
750 Clone,
751 ComputeSquaredDistance,
752 Copy,
753 Debug,
754 Deserialize,
755 MallocSizeOf,
756 PartialEq,
757 Serialize,
758 SpecifiedValueInfo,
759 ToAnimatedValue,
760 ToAnimatedZero,
761 ToComputedValue,
762 ToResolvedValue,
763 ToShmem,
764)]
765#[allow(missing_docs)]
766#[repr(C, u8)]
767pub enum GenericShapeCommand<Angle, Position, LengthPercentage> {
768 Move {
770 point: CommandEndPoint<Position, LengthPercentage>,
771 },
772 Line {
774 point: CommandEndPoint<Position, LengthPercentage>,
775 },
776 HLine {
778 #[compute(field_bound)]
779 x: AxisEndPoint<LengthPercentage>,
780 },
781 VLine {
783 #[compute(field_bound)]
784 y: AxisEndPoint<LengthPercentage>,
785 },
786 CubicCurve {
788 point: CommandEndPoint<Position, LengthPercentage>,
789 control1: ControlPoint<Position, LengthPercentage>,
790 control2: ControlPoint<Position, LengthPercentage>,
791 },
792 QuadCurve {
794 point: CommandEndPoint<Position, LengthPercentage>,
795 control1: ControlPoint<Position, LengthPercentage>,
796 },
797 SmoothCubic {
799 point: CommandEndPoint<Position, LengthPercentage>,
800 control2: ControlPoint<Position, LengthPercentage>,
801 },
802 SmoothQuad {
804 point: CommandEndPoint<Position, LengthPercentage>,
805 },
806 Arc {
808 point: CommandEndPoint<Position, LengthPercentage>,
809 radii: ArcRadii<LengthPercentage>,
810 arc_sweep: ArcSweep,
811 arc_size: ArcSize,
812 rotate: Angle,
813 },
814 Close,
816}
817
818pub use self::GenericShapeCommand as ShapeCommand;
819
820impl<Angle, Position, LengthPercentage> ToCss for ShapeCommand<Angle, Position, LengthPercentage>
821where
822 Angle: ToCss + Zero,
823 Position: ToCss,
824 LengthPercentage: PartialEq + ToCss,
825{
826 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
827 where
828 W: fmt::Write,
829 {
830 use self::ShapeCommand::*;
831 match *self {
832 Move { ref point } => {
833 dest.write_str("move ")?;
834 point.to_css(dest)
835 },
836 Line { ref point } => {
837 dest.write_str("line ")?;
838 point.to_css(dest)
839 },
840 HLine { ref x } => {
841 dest.write_str("hline ")?;
842 x.to_css(dest)
843 },
844 VLine { ref y } => {
845 dest.write_str("vline ")?;
846 y.to_css(dest)
847 },
848 CubicCurve {
849 ref point,
850 ref control1,
851 ref control2,
852 } => {
853 dest.write_str("curve ")?;
854 point.to_css(dest)?;
855 dest.write_str(" with ")?;
856 control1.to_css(dest, point.is_abs())?;
857 dest.write_char(' ')?;
858 dest.write_char('/')?;
859 dest.write_char(' ')?;
860 control2.to_css(dest, point.is_abs())
861 },
862 QuadCurve {
863 ref point,
864 ref control1,
865 } => {
866 dest.write_str("curve ")?;
867 point.to_css(dest)?;
868 dest.write_str(" with ")?;
869 control1.to_css(dest, point.is_abs())
870 },
871 SmoothCubic {
872 ref point,
873 ref control2,
874 } => {
875 dest.write_str("smooth ")?;
876 point.to_css(dest)?;
877 dest.write_str(" with ")?;
878 control2.to_css(dest, point.is_abs())
879 },
880 SmoothQuad { ref point } => {
881 dest.write_str("smooth ")?;
882 point.to_css(dest)
883 },
884 Arc {
885 ref point,
886 ref radii,
887 arc_sweep,
888 arc_size,
889 ref rotate,
890 } => {
891 dest.write_str("arc ")?;
892 point.to_css(dest)?;
893 dest.write_str(" of ")?;
894 radii.to_css(dest)?;
895
896 if matches!(arc_sweep, ArcSweep::Cw) {
897 dest.write_str(" cw")?;
898 }
899
900 if matches!(arc_size, ArcSize::Large) {
901 dest.write_str(" large")?;
902 }
903
904 if !rotate.is_zero() {
905 dest.write_str(" rotate ")?;
906 rotate.to_css(dest)?;
907 }
908 Ok(())
909 },
910 Close => dest.write_str("close"),
911 }
912 }
913}
914
915#[allow(missing_docs)]
919#[derive(
920 Animate,
921 Clone,
922 ComputeSquaredDistance,
923 Copy,
924 Debug,
925 Deserialize,
926 MallocSizeOf,
927 PartialEq,
928 Serialize,
929 SpecifiedValueInfo,
930 ToAnimatedValue,
931 ToAnimatedZero,
932 ToComputedValue,
933 ToResolvedValue,
934 ToShmem,
935)]
936#[repr(C, u8)]
937pub enum CommandEndPoint<Position, LengthPercentage> {
938 ToPosition(Position),
939 ByCoordinate(CoordinatePair<LengthPercentage>),
940}
941
942impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> {
943 #[inline]
945 pub fn is_abs(&self) -> bool {
946 matches!(self, CommandEndPoint::ToPosition(_))
947 }
948}
949
950impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> {
951 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
952 where
953 W: Write,
954 Position: ToCss,
955 LengthPercentage: ToCss,
956 {
957 match self {
958 CommandEndPoint::ToPosition(pos) => {
959 dest.write_str("to ")?;
960 pos.to_css(dest)
961 },
962 CommandEndPoint::ByCoordinate(coord) => {
963 dest.write_str("by ")?;
964 coord.to_css(dest)
965 },
966 }
967 }
968}
969
970#[allow(missing_docs)]
975#[derive(
976 Animate,
977 Clone,
978 Copy,
979 ComputeSquaredDistance,
980 Debug,
981 Deserialize,
982 MallocSizeOf,
983 PartialEq,
984 Parse,
985 Serialize,
986 SpecifiedValueInfo,
987 ToAnimatedValue,
988 ToAnimatedZero,
989 ToComputedValue,
990 ToResolvedValue,
991 ToShmem,
992)]
993#[repr(u8)]
994pub enum AxisEndPoint<LengthPercentage> {
995 ToPosition(#[compute(field_bound)] AxisPosition<LengthPercentage>),
996 ByCoordinate(LengthPercentage),
997}
998
999impl<LengthPercentage> AxisEndPoint<LengthPercentage> {
1000 #[inline]
1002 pub fn is_abs(&self) -> bool {
1003 matches!(self, AxisEndPoint::ToPosition(_))
1004 }
1005}
1006
1007impl<LengthPercentage: ToCss> ToCss for AxisEndPoint<LengthPercentage> {
1008 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1009 where
1010 W: Write,
1011 {
1012 if self.is_abs() {
1013 dest.write_str("to ")?;
1014 } else {
1015 dest.write_str("by ")?;
1016 }
1017 match self {
1018 AxisEndPoint::ToPosition(pos) => pos.to_css(dest),
1019 AxisEndPoint::ByCoordinate(coord) => coord.to_css(dest),
1020 }
1021 }
1022}
1023
1024#[allow(missing_docs)]
1029#[derive(
1030 Animate,
1031 Clone,
1032 ComputeSquaredDistance,
1033 Copy,
1034 Debug,
1035 Deserialize,
1036 MallocSizeOf,
1037 Parse,
1038 PartialEq,
1039 Serialize,
1040 SpecifiedValueInfo,
1041 ToAnimatedValue,
1042 ToAnimatedZero,
1043 ToCss,
1044 ToResolvedValue,
1045 ToShmem,
1046)]
1047#[repr(u8)]
1048pub enum AxisPosition<LengthPercentage> {
1049 LengthPercent(LengthPercentage),
1050 Keyword(AxisPositionKeyword),
1051}
1052
1053#[allow(missing_docs)]
1059#[derive(
1060 Animate,
1061 Clone,
1062 ComputeSquaredDistance,
1063 Copy,
1064 Debug,
1065 Deserialize,
1066 MallocSizeOf,
1067 Parse,
1068 PartialEq,
1069 Serialize,
1070 SpecifiedValueInfo,
1071 ToAnimatedValue,
1072 ToAnimatedZero,
1073 ToCss,
1074 ToResolvedValue,
1075 ToShmem,
1076)]
1077#[repr(u8)]
1078pub enum AxisPositionKeyword {
1079 Center,
1080 Left,
1081 Right,
1082 Top,
1083 Bottom,
1084 XStart,
1085 XEnd,
1086 YStart,
1087 YEnd,
1088}
1089
1090impl AxisPositionKeyword {
1091 #[inline]
1093 pub fn as_percentage(&self) -> Percentage {
1094 match self {
1095 Self::Center => Percentage(0.5),
1096 Self::Left | Self::Top | Self::XStart | Self::YStart => Percentage(0.),
1097 Self::Right | Self::Bottom | Self::XEnd | Self::YEnd => Percentage(1.),
1098 }
1099 }
1100}
1101
1102#[allow(missing_docs)]
1107#[derive(
1108 AddAssign,
1109 Animate,
1110 Clone,
1111 ComputeSquaredDistance,
1112 Copy,
1113 Debug,
1114 Deserialize,
1115 MallocSizeOf,
1116 PartialEq,
1117 Serialize,
1118 SpecifiedValueInfo,
1119 ToAnimatedValue,
1120 ToAnimatedZero,
1121 ToComputedValue,
1122 ToCss,
1123 ToResolvedValue,
1124 ToShmem,
1125)]
1126#[repr(C)]
1127pub struct CoordinatePair<LengthPercentage> {
1128 pub x: LengthPercentage,
1129 pub y: LengthPercentage,
1130}
1131
1132impl<LengthPercentage> CoordinatePair<LengthPercentage> {
1133 #[inline]
1135 pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self {
1136 Self { x, y }
1137 }
1138}
1139
1140#[allow(missing_docs)]
1144#[derive(
1145 Animate,
1146 Clone,
1147 Copy,
1148 ComputeSquaredDistance,
1149 Debug,
1150 Deserialize,
1151 MallocSizeOf,
1152 PartialEq,
1153 Serialize,
1154 SpecifiedValueInfo,
1155 ToAnimatedValue,
1156 ToAnimatedZero,
1157 ToComputedValue,
1158 ToResolvedValue,
1159 ToShmem,
1160)]
1161#[repr(C, u8)]
1162pub enum ControlPoint<Position, LengthPercentage> {
1163 Absolute(Position),
1164 Relative(RelativeControlPoint<LengthPercentage>),
1165}
1166
1167impl<Position, LengthPercentage> ControlPoint<Position, LengthPercentage> {
1168 pub fn to_css<W>(&self, dest: &mut CssWriter<W>, is_end_point_abs: bool) -> fmt::Result
1170 where
1171 W: Write,
1172 Position: ToCss,
1173 LengthPercentage: ToCss,
1174 {
1175 match self {
1176 ControlPoint::Absolute(pos) => pos.to_css(dest),
1177 ControlPoint::Relative(point) => point.to_css(dest, is_end_point_abs),
1178 }
1179 }
1180}
1181
1182#[allow(missing_docs)]
1186#[derive(
1187 Animate,
1188 Clone,
1189 Copy,
1190 Debug,
1191 Deserialize,
1192 MallocSizeOf,
1193 PartialEq,
1194 Serialize,
1195 SpecifiedValueInfo,
1196 ToAnimatedValue,
1197 ToAnimatedZero,
1198 ToComputedValue,
1199 ToResolvedValue,
1200 ToShmem,
1201)]
1202#[repr(C)]
1203pub struct RelativeControlPoint<LengthPercentage> {
1204 pub coord: CoordinatePair<LengthPercentage>,
1205 pub reference: ControlReference,
1206}
1207
1208impl<LengthPercentage: ToCss> RelativeControlPoint<LengthPercentage> {
1209 fn to_css<W>(&self, dest: &mut CssWriter<W>, is_end_point_abs: bool) -> fmt::Result
1210 where
1211 W: Write,
1212 {
1213 self.coord.to_css(dest)?;
1214 match self.reference {
1215 ControlReference::Origin if is_end_point_abs => Ok(()),
1216 ControlReference::Start if !is_end_point_abs => Ok(()),
1217 other => {
1218 dest.write_str(" from ")?;
1219 other.to_css(dest)
1220 },
1221 }
1222 }
1223}
1224
1225impl<LengthPercentage: ComputeSquaredDistance> ComputeSquaredDistance
1226 for RelativeControlPoint<LengthPercentage>
1227{
1228 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1229 self.coord.compute_squared_distance(&other.coord)
1230 }
1231}
1232
1233#[allow(missing_docs)]
1240#[derive(
1241 Animate,
1242 Clone,
1243 Copy,
1244 Debug,
1245 Deserialize,
1246 Eq,
1247 MallocSizeOf,
1248 PartialEq,
1249 Parse,
1250 Serialize,
1251 SpecifiedValueInfo,
1252 ToAnimatedValue,
1253 ToAnimatedZero,
1254 ToComputedValue,
1255 ToCss,
1256 ToResolvedValue,
1257 ToShmem,
1258)]
1259#[repr(C)]
1260pub enum ControlReference {
1261 Start,
1262 End,
1263 Origin,
1264}
1265
1266#[allow(missing_docs)]
1273#[derive(
1274 Animate,
1275 Clone,
1276 ComputeSquaredDistance,
1277 Copy,
1278 Debug,
1279 Deserialize,
1280 MallocSizeOf,
1281 PartialEq,
1282 Serialize,
1283 SpecifiedValueInfo,
1284 ToAnimatedValue,
1285 ToAnimatedZero,
1286 ToComputedValue,
1287 ToCss,
1288 ToResolvedValue,
1289 ToShmem,
1290)]
1291#[repr(C)]
1292pub struct ArcRadii<LengthPercentage> {
1293 pub rx: LengthPercentage,
1294 pub ry: Optional<LengthPercentage>,
1295}
1296
1297#[derive(
1301 Clone,
1302 Copy,
1303 Debug,
1304 Deserialize,
1305 FromPrimitive,
1306 MallocSizeOf,
1307 Parse,
1308 PartialEq,
1309 Serialize,
1310 SpecifiedValueInfo,
1311 ToAnimatedValue,
1312 ToAnimatedZero,
1313 ToComputedValue,
1314 ToCss,
1315 ToResolvedValue,
1316 ToShmem,
1317)]
1318#[repr(u8)]
1319pub enum ArcSweep {
1320 Ccw = 0,
1322 Cw = 1,
1324}
1325
1326impl Animate for ArcSweep {
1327 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1328 use num_traits::FromPrimitive;
1329 let progress = procedure.weights().1 as f32 as f64;
1333 let procedure = Procedure::Interpolate { progress };
1334 (*self as i32 as f32)
1335 .animate(&(*other as i32 as f32), procedure)
1336 .map(|v| ArcSweep::from_u8((v > 0.) as u8).unwrap_or(ArcSweep::Ccw))
1337 }
1338}
1339
1340impl ComputeSquaredDistance for ArcSweep {
1341 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1342 (*self as i32).compute_squared_distance(&(*other as i32))
1343 }
1344}
1345
1346#[derive(
1350 Clone,
1351 Copy,
1352 Debug,
1353 Deserialize,
1354 FromPrimitive,
1355 MallocSizeOf,
1356 Parse,
1357 PartialEq,
1358 Serialize,
1359 SpecifiedValueInfo,
1360 ToAnimatedValue,
1361 ToAnimatedZero,
1362 ToComputedValue,
1363 ToCss,
1364 ToResolvedValue,
1365 ToShmem,
1366)]
1367#[repr(u8)]
1368pub enum ArcSize {
1369 Small = 0,
1371 Large = 1,
1373}
1374
1375impl Animate for ArcSize {
1376 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1377 use num_traits::FromPrimitive;
1378 let progress = procedure.weights().1 as f32 as f64;
1382 let procedure = Procedure::Interpolate { progress };
1383 (*self as i32 as f32)
1384 .animate(&(*other as i32 as f32), procedure)
1385 .map(|v| ArcSize::from_u8((v > 0.) as u8).unwrap_or(ArcSize::Small))
1386 }
1387}
1388
1389impl ComputeSquaredDistance for ArcSize {
1390 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1391 (*self as i32).compute_squared_distance(&(*other as i32))
1392 }
1393}