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