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