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