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)]
163pub enum GenericShapeOutside<BasicShape, I> {
164 #[animation(error)]
165 None,
166 #[animation(error)]
167 Image(I),
168 #[typed(skip)]
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 #[animation(error)]
340 FarthestCorner,
341 #[animation(error)]
342 ClosestCorner,
343}
344
345pub use self::GenericShapeRadius as ShapeRadius;
346
347#[derive(
351 Clone,
352 Debug,
353 Deserialize,
354 MallocSizeOf,
355 PartialEq,
356 Serialize,
357 SpecifiedValueInfo,
358 ToAnimatedValue,
359 ToComputedValue,
360 ToCss,
361 ToResolvedValue,
362 ToShmem,
363)]
364#[css(comma, function = "polygon")]
365#[repr(C)]
366pub struct GenericPolygon<LengthPercentage> {
367 #[css(skip_if = "is_default")]
369 pub fill: FillRule,
370 #[css(iterable)]
372 pub coordinates: crate::OwnedSlice<PolygonCoord<LengthPercentage>>,
373}
374
375pub use self::GenericPolygon as Polygon;
376
377#[derive(
379 Animate,
380 Clone,
381 ComputeSquaredDistance,
382 Debug,
383 Deserialize,
384 MallocSizeOf,
385 PartialEq,
386 Serialize,
387 SpecifiedValueInfo,
388 ToAnimatedValue,
389 ToComputedValue,
390 ToCss,
391 ToResolvedValue,
392 ToShmem,
393)]
394#[repr(C)]
395pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercentage);
396
397#[derive(
399 Clone,
400 ComputeSquaredDistance,
401 Debug,
402 Deserialize,
403 MallocSizeOf,
404 PartialEq,
405 Serialize,
406 SpecifiedValueInfo,
407 ToAnimatedValue,
408 ToComputedValue,
409 ToCss,
410 ToResolvedValue,
411 ToShmem,
412)]
413#[repr(C, u8)]
414pub enum GenericPathOrShapeFunction<Angle, Position, LengthPercentage> {
415 Path(Path),
417 Shape(
419 #[css(field_bound)]
420 #[compute(field_bound)]
421 Shape<Angle, Position, LengthPercentage>,
422 ),
423}
424
425#[allow(missing_docs)]
430#[derive(
431 Animate,
432 Clone,
433 ComputeSquaredDistance,
434 Copy,
435 Debug,
436 Deserialize,
437 Eq,
438 MallocSizeOf,
439 Parse,
440 PartialEq,
441 Serialize,
442 SpecifiedValueInfo,
443 ToAnimatedValue,
444 ToComputedValue,
445 ToCss,
446 ToResolvedValue,
447 ToShmem,
448 ToTyped,
449)]
450#[repr(u8)]
451pub enum FillRule {
452 Nonzero,
453 Evenodd,
454}
455
456#[derive(
460 Animate,
461 Clone,
462 ComputeSquaredDistance,
463 Debug,
464 Deserialize,
465 MallocSizeOf,
466 PartialEq,
467 Serialize,
468 SpecifiedValueInfo,
469 ToAnimatedValue,
470 ToComputedValue,
471 ToCss,
472 ToResolvedValue,
473 ToShmem,
474)]
475#[css(comma, function = "path")]
476#[repr(C)]
477pub struct Path {
478 #[css(skip_if = "is_default")]
480 pub fill: FillRule,
481 pub path: SVGPathData,
483}
484
485impl Path {
486 #[inline]
488 pub fn commands(&self) -> &[PathCommand] {
489 self.path.commands()
490 }
491}
492
493impl<B, U> ToAnimatedZero for ClipPath<B, U> {
494 fn to_animated_zero(&self) -> Result<Self, ()> {
495 Err(())
496 }
497}
498
499impl<B, U> ToAnimatedZero for ShapeOutside<B, U> {
500 fn to_animated_zero(&self) -> Result<Self, ()> {
501 Err(())
502 }
503}
504
505impl<Length> ToCss for InsetRect<Length>
506where
507 Length: ToCss + PartialEq + Zero,
508{
509 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
510 where
511 W: Write,
512 {
513 dest.write_str("inset(")?;
514 self.rect.to_css(dest)?;
515 if !self.round.is_zero() {
516 dest.write_str(" round ")?;
517 self.round.to_css(dest)?;
518 }
519 dest.write_char(')')
520 }
521}
522
523impl<Position, LengthPercentage> ToCss for Circle<Position, LengthPercentage>
524where
525 LengthPercentage: ToCss + PartialEq,
526 Position: ToCss,
527{
528 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
529 where
530 W: Write,
531 {
532 let has_radius = self.radius != Default::default();
533
534 dest.write_str("circle(")?;
535 if has_radius {
536 self.radius.to_css(dest)?;
537 }
538
539 if !matches!(self.position, GenericPositionOrAuto::Auto) {
542 if has_radius {
543 dest.write_char(' ')?;
544 }
545 dest.write_str("at ")?;
546 self.position.to_css(dest)?;
547 }
548 dest.write_char(')')
549 }
550}
551
552impl<Position, LengthPercentage> ToCss for Ellipse<Position, LengthPercentage>
553where
554 LengthPercentage: ToCss + PartialEq,
555 Position: ToCss,
556{
557 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
558 where
559 W: Write,
560 {
561 let has_radii =
562 self.semiaxis_x != Default::default() || self.semiaxis_y != Default::default();
563
564 dest.write_str("ellipse(")?;
565 if has_radii {
566 self.semiaxis_x.to_css(dest)?;
567 dest.write_char(' ')?;
568 self.semiaxis_y.to_css(dest)?;
569 }
570
571 if !matches!(self.position, GenericPositionOrAuto::Auto) {
574 if has_radii {
575 dest.write_char(' ')?;
576 }
577 dest.write_str("at ")?;
578 self.position.to_css(dest)?;
579 }
580 dest.write_char(')')
581 }
582}
583
584impl<L> Default for ShapeRadius<L> {
585 #[inline]
586 fn default() -> Self {
587 ShapeRadius::ClosestSide
588 }
589}
590
591impl<L> Animate for Polygon<L>
592where
593 L: Animate,
594{
595 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
596 if self.fill != other.fill {
597 return Err(());
598 }
599 let coordinates =
600 lists::by_computed_value::animate(&self.coordinates, &other.coordinates, procedure)?;
601 Ok(Polygon {
602 fill: self.fill,
603 coordinates,
604 })
605 }
606}
607
608impl<L> ComputeSquaredDistance for Polygon<L>
609where
610 L: ComputeSquaredDistance,
611{
612 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
613 if self.fill != other.fill {
614 return Err(());
615 }
616 lists::by_computed_value::squared_distance(&self.coordinates, &other.coordinates)
617 }
618}
619
620impl Default for FillRule {
621 #[inline]
622 fn default() -> Self {
623 FillRule::Nonzero
624 }
625}
626
627#[inline]
628fn is_default<T: Default + PartialEq>(fill: &T) -> bool {
629 *fill == Default::default()
630}
631
632#[derive(
637 Clone,
638 Debug,
639 Deserialize,
640 MallocSizeOf,
641 PartialEq,
642 Serialize,
643 SpecifiedValueInfo,
644 ToAnimatedValue,
645 ToComputedValue,
646 ToResolvedValue,
647 ToShmem,
648)]
649#[repr(C)]
650pub struct Shape<Angle, Position, LengthPercentage> {
651 pub fill: FillRule,
653 #[compute(field_bound)]
657 pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, Position, LengthPercentage>>,
658}
659
660impl<Angle, Position, LengthPercentage> Shape<Angle, Position, LengthPercentage> {
661 #[inline]
663 pub fn commands(&self) -> &[GenericShapeCommand<Angle, Position, LengthPercentage>] {
664 &self.commands
665 }
666}
667
668impl<Angle, Position, LengthPercentage> Animate for Shape<Angle, Position, LengthPercentage>
669where
670 Angle: 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, Position, LengthPercentage> ComputeSquaredDistance
688 for Shape<Angle, Position, LengthPercentage>
689where
690 Angle: ComputeSquaredDistance,
691 Position: ComputeSquaredDistance,
692 LengthPercentage: ComputeSquaredDistance,
693{
694 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
695 if self.fill != other.fill {
696 return Err(());
697 }
698 lists::by_computed_value::squared_distance(&self.commands, &other.commands)
699 }
700}
701
702impl<Angle, Position, LengthPercentage> ToCss for Shape<Angle, Position, LengthPercentage>
703where
704 Angle: ToCss + Zero,
705 Position: ToCss,
706 LengthPercentage: PartialEq + ToCss,
707{
708 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
709 where
710 W: Write,
711 {
712 use style_traits::values::SequenceWriter;
713
714 debug_assert!(self.commands.len() > 1);
716
717 dest.write_str("shape(")?;
718 if !is_default(&self.fill) {
719 self.fill.to_css(dest)?;
720 dest.write_char(' ')?;
721 }
722 dest.write_str("from ")?;
723 match &self.commands[0] {
724 ShapeCommand::Move {
725 point: CommandEndPoint::ToPosition(pos),
726 } => pos.to_css(dest)?,
727 ShapeCommand::Move {
728 point: CommandEndPoint::ByCoordinate(coord),
729 } => coord.to_css(dest)?,
730 _ => unreachable!("The first command must be move"),
731 }
732 dest.write_str(", ")?;
733 {
734 let mut writer = SequenceWriter::new(dest, ", ");
735 for command in self.commands.iter().skip(1) {
736 writer.item(command)?;
737 }
738 }
739 dest.write_char(')')
740 }
741}
742
743#[derive(
748 Animate,
749 Clone,
750 ComputeSquaredDistance,
751 Copy,
752 Debug,
753 Deserialize,
754 MallocSizeOf,
755 PartialEq,
756 Serialize,
757 SpecifiedValueInfo,
758 ToAnimatedValue,
759 ToAnimatedZero,
760 ToComputedValue,
761 ToResolvedValue,
762 ToShmem,
763)]
764#[allow(missing_docs)]
765#[repr(C, u8)]
766pub enum GenericShapeCommand<Angle, Position, LengthPercentage> {
767 Move {
769 point: CommandEndPoint<Position, LengthPercentage>,
770 },
771 Line {
773 point: CommandEndPoint<Position, LengthPercentage>,
774 },
775 HLine {
777 #[compute(field_bound)]
778 x: AxisEndPoint<LengthPercentage>,
779 },
780 VLine {
782 #[compute(field_bound)]
783 y: AxisEndPoint<LengthPercentage>,
784 },
785 CubicCurve {
787 point: CommandEndPoint<Position, LengthPercentage>,
788 control1: ControlPoint<Position, LengthPercentage>,
789 control2: ControlPoint<Position, LengthPercentage>,
790 },
791 QuadCurve {
793 point: CommandEndPoint<Position, LengthPercentage>,
794 control1: ControlPoint<Position, LengthPercentage>,
795 },
796 SmoothCubic {
798 point: CommandEndPoint<Position, LengthPercentage>,
799 control2: ControlPoint<Position, LengthPercentage>,
800 },
801 SmoothQuad {
803 point: CommandEndPoint<Position, LengthPercentage>,
804 },
805 Arc {
807 point: CommandEndPoint<Position, LengthPercentage>,
808 radii: ArcRadii<LengthPercentage>,
809 arc_sweep: ArcSweep,
810 arc_size: ArcSize,
811 rotate: Angle,
812 },
813 Close,
815}
816
817pub use self::GenericShapeCommand as ShapeCommand;
818
819impl<Angle, Position, LengthPercentage> ToCss for ShapeCommand<Angle, Position, LengthPercentage>
820where
821 Angle: ToCss + Zero,
822 Position: ToCss,
823 LengthPercentage: PartialEq + ToCss,
824{
825 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
826 where
827 W: fmt::Write,
828 {
829 use self::ShapeCommand::*;
830 match *self {
831 Move { ref point } => {
832 dest.write_str("move ")?;
833 point.to_css(dest)
834 },
835 Line { ref point } => {
836 dest.write_str("line ")?;
837 point.to_css(dest)
838 },
839 HLine { ref x } => {
840 dest.write_str("hline ")?;
841 x.to_css(dest)
842 },
843 VLine { ref y } => {
844 dest.write_str("vline ")?;
845 y.to_css(dest)
846 },
847 CubicCurve {
848 ref point,
849 ref control1,
850 ref control2,
851 } => {
852 dest.write_str("curve ")?;
853 point.to_css(dest)?;
854 dest.write_str(" with ")?;
855 control1.to_css(dest, point.is_abs())?;
856 dest.write_char(' ')?;
857 dest.write_char('/')?;
858 dest.write_char(' ')?;
859 control2.to_css(dest, point.is_abs())
860 },
861 QuadCurve {
862 ref point,
863 ref control1,
864 } => {
865 dest.write_str("curve ")?;
866 point.to_css(dest)?;
867 dest.write_str(" with ")?;
868 control1.to_css(dest, point.is_abs())
869 },
870 SmoothCubic {
871 ref point,
872 ref control2,
873 } => {
874 dest.write_str("smooth ")?;
875 point.to_css(dest)?;
876 dest.write_str(" with ")?;
877 control2.to_css(dest, point.is_abs())
878 },
879 SmoothQuad { ref point } => {
880 dest.write_str("smooth ")?;
881 point.to_css(dest)
882 },
883 Arc {
884 ref point,
885 ref radii,
886 arc_sweep,
887 arc_size,
888 ref rotate,
889 } => {
890 dest.write_str("arc ")?;
891 point.to_css(dest)?;
892 dest.write_str(" of ")?;
893 radii.to_css(dest)?;
894
895 if matches!(arc_sweep, ArcSweep::Cw) {
896 dest.write_str(" cw")?;
897 }
898
899 if matches!(arc_size, ArcSize::Large) {
900 dest.write_str(" large")?;
901 }
902
903 if !rotate.is_zero() {
904 dest.write_str(" rotate ")?;
905 rotate.to_css(dest)?;
906 }
907 Ok(())
908 },
909 Close => dest.write_str("close"),
910 }
911 }
912}
913
914#[allow(missing_docs)]
918#[derive(
919 Animate,
920 Clone,
921 ComputeSquaredDistance,
922 Copy,
923 Debug,
924 Deserialize,
925 MallocSizeOf,
926 PartialEq,
927 Serialize,
928 SpecifiedValueInfo,
929 ToAnimatedValue,
930 ToAnimatedZero,
931 ToComputedValue,
932 ToResolvedValue,
933 ToShmem,
934)]
935#[repr(C, u8)]
936pub enum CommandEndPoint<Position, LengthPercentage> {
937 ToPosition(Position),
938 ByCoordinate(CoordinatePair<LengthPercentage>),
939}
940
941impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> {
942 #[inline]
944 pub fn is_abs(&self) -> bool {
945 matches!(self, CommandEndPoint::ToPosition(_))
946 }
947}
948
949impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> {
950 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
951 where
952 W: Write,
953 Position: ToCss,
954 LengthPercentage: ToCss,
955 {
956 match self {
957 CommandEndPoint::ToPosition(pos) => {
958 dest.write_str("to ")?;
959 pos.to_css(dest)
960 },
961 CommandEndPoint::ByCoordinate(coord) => {
962 dest.write_str("by ")?;
963 coord.to_css(dest)
964 },
965 }
966 }
967}
968
969#[allow(missing_docs)]
974#[derive(
975 Animate,
976 Clone,
977 Copy,
978 ComputeSquaredDistance,
979 Debug,
980 Deserialize,
981 MallocSizeOf,
982 PartialEq,
983 Parse,
984 Serialize,
985 SpecifiedValueInfo,
986 ToAnimatedValue,
987 ToAnimatedZero,
988 ToComputedValue,
989 ToResolvedValue,
990 ToShmem,
991)]
992#[repr(u8)]
993pub enum AxisEndPoint<LengthPercentage> {
994 ToPosition(#[compute(field_bound)] AxisPosition<LengthPercentage>),
995 ByCoordinate(LengthPercentage),
996}
997
998impl<LengthPercentage> AxisEndPoint<LengthPercentage> {
999 #[inline]
1001 pub fn is_abs(&self) -> bool {
1002 matches!(self, AxisEndPoint::ToPosition(_))
1003 }
1004}
1005
1006impl<LengthPercentage: ToCss> ToCss for AxisEndPoint<LengthPercentage> {
1007 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1008 where
1009 W: Write,
1010 {
1011 if self.is_abs() {
1012 dest.write_str("to ")?;
1013 } else {
1014 dest.write_str("by ")?;
1015 }
1016 match self {
1017 AxisEndPoint::ToPosition(pos) => pos.to_css(dest),
1018 AxisEndPoint::ByCoordinate(coord) => coord.to_css(dest),
1019 }
1020 }
1021}
1022
1023#[allow(missing_docs)]
1028#[derive(
1029 Animate,
1030 Clone,
1031 ComputeSquaredDistance,
1032 Copy,
1033 Debug,
1034 Deserialize,
1035 MallocSizeOf,
1036 Parse,
1037 PartialEq,
1038 Serialize,
1039 SpecifiedValueInfo,
1040 ToAnimatedValue,
1041 ToAnimatedZero,
1042 ToCss,
1043 ToResolvedValue,
1044 ToShmem,
1045)]
1046#[repr(u8)]
1047pub enum AxisPosition<LengthPercentage> {
1048 LengthPercent(LengthPercentage),
1049 Keyword(AxisPositionKeyword),
1050}
1051
1052#[allow(missing_docs)]
1058#[derive(
1059 Animate,
1060 Clone,
1061 ComputeSquaredDistance,
1062 Copy,
1063 Debug,
1064 Deserialize,
1065 MallocSizeOf,
1066 Parse,
1067 PartialEq,
1068 Serialize,
1069 SpecifiedValueInfo,
1070 ToAnimatedValue,
1071 ToAnimatedZero,
1072 ToCss,
1073 ToResolvedValue,
1074 ToShmem,
1075)]
1076#[repr(u8)]
1077pub enum AxisPositionKeyword {
1078 Center,
1079 Left,
1080 Right,
1081 Top,
1082 Bottom,
1083 XStart,
1084 XEnd,
1085 YStart,
1086 YEnd,
1087}
1088
1089impl AxisPositionKeyword {
1090 #[inline]
1092 pub fn as_percentage(&self) -> Percentage {
1093 match self {
1094 Self::Center => Percentage(0.5),
1095 Self::Left | Self::Top | Self::XStart | Self::YStart => Percentage(0.),
1096 Self::Right | Self::Bottom | Self::XEnd | Self::YEnd => Percentage(1.),
1097 }
1098 }
1099}
1100
1101#[allow(missing_docs)]
1106#[derive(
1107 AddAssign,
1108 Animate,
1109 Clone,
1110 ComputeSquaredDistance,
1111 Copy,
1112 Debug,
1113 Deserialize,
1114 MallocSizeOf,
1115 PartialEq,
1116 Serialize,
1117 SpecifiedValueInfo,
1118 ToAnimatedValue,
1119 ToAnimatedZero,
1120 ToComputedValue,
1121 ToCss,
1122 ToResolvedValue,
1123 ToShmem,
1124)]
1125#[repr(C)]
1126pub struct CoordinatePair<LengthPercentage> {
1127 pub x: LengthPercentage,
1128 pub y: LengthPercentage,
1129}
1130
1131impl<LengthPercentage> CoordinatePair<LengthPercentage> {
1132 #[inline]
1134 pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self {
1135 Self { x, y }
1136 }
1137}
1138
1139#[allow(missing_docs)]
1143#[derive(
1144 Animate,
1145 Clone,
1146 Copy,
1147 ComputeSquaredDistance,
1148 Debug,
1149 Deserialize,
1150 MallocSizeOf,
1151 PartialEq,
1152 Serialize,
1153 SpecifiedValueInfo,
1154 ToAnimatedValue,
1155 ToAnimatedZero,
1156 ToComputedValue,
1157 ToResolvedValue,
1158 ToShmem,
1159)]
1160#[repr(C, u8)]
1161pub enum ControlPoint<Position, LengthPercentage> {
1162 Absolute(Position),
1163 Relative(RelativeControlPoint<LengthPercentage>),
1164}
1165
1166impl<Position, LengthPercentage> ControlPoint<Position, LengthPercentage> {
1167 pub fn to_css<W>(&self, dest: &mut CssWriter<W>, is_end_point_abs: bool) -> fmt::Result
1169 where
1170 W: Write,
1171 Position: ToCss,
1172 LengthPercentage: ToCss,
1173 {
1174 match self {
1175 ControlPoint::Absolute(pos) => pos.to_css(dest),
1176 ControlPoint::Relative(point) => point.to_css(dest, is_end_point_abs),
1177 }
1178 }
1179}
1180
1181#[allow(missing_docs)]
1185#[derive(
1186 Animate,
1187 Clone,
1188 Copy,
1189 Debug,
1190 Deserialize,
1191 MallocSizeOf,
1192 PartialEq,
1193 Serialize,
1194 SpecifiedValueInfo,
1195 ToAnimatedValue,
1196 ToAnimatedZero,
1197 ToComputedValue,
1198 ToResolvedValue,
1199 ToShmem,
1200)]
1201#[repr(C)]
1202pub struct RelativeControlPoint<LengthPercentage> {
1203 pub coord: CoordinatePair<LengthPercentage>,
1204 pub reference: ControlReference,
1205}
1206
1207impl<LengthPercentage: ToCss> RelativeControlPoint<LengthPercentage> {
1208 fn to_css<W>(&self, dest: &mut CssWriter<W>, is_end_point_abs: bool) -> fmt::Result
1209 where
1210 W: Write,
1211 {
1212 self.coord.to_css(dest)?;
1213 match self.reference {
1214 ControlReference::Origin if is_end_point_abs => Ok(()),
1215 ControlReference::Start if !is_end_point_abs => Ok(()),
1216 other => {
1217 dest.write_str(" from ")?;
1218 other.to_css(dest)
1219 },
1220 }
1221 }
1222}
1223
1224impl<LengthPercentage: ComputeSquaredDistance> ComputeSquaredDistance
1225 for RelativeControlPoint<LengthPercentage>
1226{
1227 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1228 self.coord.compute_squared_distance(&other.coord)
1229 }
1230}
1231
1232#[allow(missing_docs)]
1239#[derive(
1240 Animate,
1241 Clone,
1242 Copy,
1243 Debug,
1244 Deserialize,
1245 Eq,
1246 MallocSizeOf,
1247 PartialEq,
1248 Parse,
1249 Serialize,
1250 SpecifiedValueInfo,
1251 ToAnimatedValue,
1252 ToAnimatedZero,
1253 ToComputedValue,
1254 ToCss,
1255 ToResolvedValue,
1256 ToShmem,
1257)]
1258#[repr(C)]
1259pub enum ControlReference {
1260 Start,
1261 End,
1262 Origin,
1263}
1264
1265#[allow(missing_docs)]
1272#[derive(
1273 Animate,
1274 Clone,
1275 ComputeSquaredDistance,
1276 Copy,
1277 Debug,
1278 Deserialize,
1279 MallocSizeOf,
1280 PartialEq,
1281 Serialize,
1282 SpecifiedValueInfo,
1283 ToAnimatedValue,
1284 ToAnimatedZero,
1285 ToComputedValue,
1286 ToCss,
1287 ToResolvedValue,
1288 ToShmem,
1289)]
1290#[repr(C)]
1291pub struct ArcRadii<LengthPercentage> {
1292 pub rx: LengthPercentage,
1293 pub ry: Optional<LengthPercentage>,
1294}
1295
1296#[derive(
1300 Clone,
1301 Copy,
1302 Debug,
1303 Deserialize,
1304 FromPrimitive,
1305 MallocSizeOf,
1306 Parse,
1307 PartialEq,
1308 Serialize,
1309 SpecifiedValueInfo,
1310 ToAnimatedValue,
1311 ToAnimatedZero,
1312 ToComputedValue,
1313 ToCss,
1314 ToResolvedValue,
1315 ToShmem,
1316)]
1317#[repr(u8)]
1318pub enum ArcSweep {
1319 Ccw = 0,
1321 Cw = 1,
1323}
1324
1325impl Animate for ArcSweep {
1326 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1327 use num_traits::FromPrimitive;
1328 let progress = procedure.weights().1 as f32 as f64;
1332 let procedure = Procedure::Interpolate { progress };
1333 (*self as i32 as f32)
1334 .animate(&(*other as i32 as f32), procedure)
1335 .map(|v| ArcSweep::from_u8((v > 0.) as u8).unwrap_or(ArcSweep::Ccw))
1336 }
1337}
1338
1339impl ComputeSquaredDistance for ArcSweep {
1340 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1341 (*self as i32).compute_squared_distance(&(*other as i32))
1342 }
1343}
1344
1345#[derive(
1349 Clone,
1350 Copy,
1351 Debug,
1352 Deserialize,
1353 FromPrimitive,
1354 MallocSizeOf,
1355 Parse,
1356 PartialEq,
1357 Serialize,
1358 SpecifiedValueInfo,
1359 ToAnimatedValue,
1360 ToAnimatedZero,
1361 ToComputedValue,
1362 ToCss,
1363 ToResolvedValue,
1364 ToShmem,
1365)]
1366#[repr(u8)]
1367pub enum ArcSize {
1368 Small = 0,
1370 Large = 1,
1372}
1373
1374impl Animate for ArcSize {
1375 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1376 use num_traits::FromPrimitive;
1377 let progress = procedure.weights().1 as f32 as f64;
1381 let procedure = Procedure::Interpolate { progress };
1382 (*self as i32 as f32)
1383 .animate(&(*other as i32 as f32), procedure)
1384 .map(|v| ArcSize::from_u8((v > 0.) as u8).unwrap_or(ArcSize::Small))
1385 }
1386}
1387
1388impl ComputeSquaredDistance for ArcSize {
1389 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1390 (*self as i32).compute_squared_distance(&(*other as i32))
1391 }
1392}