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