1use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero};
9use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
10use crate::values::generics::{
11 border::GenericBorderRadius,
12 position::{GenericPosition, GenericPositionOrAuto},
13 rect::Rect,
14 NonNegative, Optional,
15};
16use crate::values::specified::svg_path::{PathCommand, SVGPathData};
17use crate::Zero;
18use std::fmt::{self, Write};
19use style_traits::{CssWriter, ToCss};
20
21pub type ShapePosition<LengthPercentage> = GenericPosition<LengthPercentage, LengthPercentage>;
23
24#[allow(missing_docs)]
26#[derive(
27 Animate,
28 Clone,
29 ComputeSquaredDistance,
30 Copy,
31 Debug,
32 MallocSizeOf,
33 PartialEq,
34 Parse,
35 SpecifiedValueInfo,
36 ToAnimatedValue,
37 ToComputedValue,
38 ToCss,
39 ToResolvedValue,
40 ToShmem,
41 ToTyped,
42)]
43#[repr(u8)]
44#[typed_value(derive_fields)]
45pub enum ShapeGeometryBox {
46 #[css(skip)]
53 ElementDependent,
54 FillBox,
55 StrokeBox,
56 ViewBox,
57 ShapeBox(ShapeBox),
58}
59
60impl Default for ShapeGeometryBox {
61 fn default() -> Self {
62 Self::ElementDependent
63 }
64}
65
66#[inline]
68fn is_default_box_for_clip_path(b: &ShapeGeometryBox) -> bool {
69 matches!(b, ShapeGeometryBox::ElementDependent)
72 || matches!(b, ShapeGeometryBox::ShapeBox(ShapeBox::BorderBox))
73}
74
75#[allow(missing_docs)]
77#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
78#[derive(
79 Animate,
80 Clone,
81 Copy,
82 ComputeSquaredDistance,
83 Debug,
84 Eq,
85 MallocSizeOf,
86 Parse,
87 PartialEq,
88 SpecifiedValueInfo,
89 ToAnimatedValue,
90 ToComputedValue,
91 ToCss,
92 ToResolvedValue,
93 ToShmem,
94 ToTyped,
95)]
96#[repr(u8)]
97pub enum ShapeBox {
98 MarginBox,
99 BorderBox,
100 PaddingBox,
101 ContentBox,
102}
103
104impl Default for ShapeBox {
105 fn default() -> Self {
106 ShapeBox::MarginBox
107 }
108}
109
110#[allow(missing_docs)]
112#[derive(
113 Animate,
114 Clone,
115 ComputeSquaredDistance,
116 Debug,
117 MallocSizeOf,
118 PartialEq,
119 SpecifiedValueInfo,
120 ToAnimatedValue,
121 ToComputedValue,
122 ToCss,
123 ToResolvedValue,
124 ToShmem,
125 ToTyped,
126)]
127#[animation(no_bound(U))]
128#[repr(u8)]
129#[typed_value(derive_fields)]
130pub enum GenericClipPath<BasicShape, U> {
131 #[animation(error)]
132 None,
133 #[animation(error)]
134 #[typed_value(todo)]
138 Url(U),
139 #[typed_value(skip)]
140 Shape(
141 #[animation(field_bound)] Box<BasicShape>,
142 #[css(skip_if = "is_default_box_for_clip_path")] ShapeGeometryBox,
143 ),
144 #[animation(error)]
145 Box(ShapeGeometryBox),
146}
147
148pub use self::GenericClipPath as ClipPath;
149
150#[allow(missing_docs)]
152#[derive(
153 Animate,
154 Clone,
155 ComputeSquaredDistance,
156 Debug,
157 MallocSizeOf,
158 PartialEq,
159 SpecifiedValueInfo,
160 ToAnimatedValue,
161 ToComputedValue,
162 ToCss,
163 ToResolvedValue,
164 ToShmem,
165 ToTyped,
166)]
167#[animation(no_bound(I))]
168#[repr(u8)]
169pub enum GenericShapeOutside<BasicShape, I> {
170 #[animation(error)]
171 None,
172 #[animation(error)]
173 Image(I),
174 Shape(Box<BasicShape>, #[css(skip_if = "is_default")] ShapeBox),
175 #[animation(error)]
176 Box(ShapeBox),
177}
178
179pub use self::GenericShapeOutside as ShapeOutside;
180
181#[derive(
185 Animate,
186 Clone,
187 ComputeSquaredDistance,
188 Debug,
189 Deserialize,
190 MallocSizeOf,
191 PartialEq,
192 Serialize,
193 SpecifiedValueInfo,
194 ToAnimatedValue,
195 ToComputedValue,
196 ToCss,
197 ToResolvedValue,
198 ToShmem,
199)]
200#[repr(C, u8)]
201pub enum GenericBasicShape<Angle, Position, LengthPercentage, BasicShapeRect> {
202 Rect(BasicShapeRect),
204 Circle(
206 #[animation(field_bound)]
207 #[css(field_bound)]
208 #[shmem(field_bound)]
209 Circle<LengthPercentage>,
210 ),
211 Ellipse(
213 #[animation(field_bound)]
214 #[css(field_bound)]
215 #[shmem(field_bound)]
216 Ellipse<LengthPercentage>,
217 ),
218 Polygon(GenericPolygon<LengthPercentage>),
220 PathOrShape(
222 #[animation(field_bound)]
223 #[css(field_bound)]
224 GenericPathOrShapeFunction<Angle, Position, LengthPercentage>,
225 ),
226}
227
228pub use self::GenericBasicShape as BasicShape;
229
230#[allow(missing_docs)]
232#[derive(
233 Animate,
234 Clone,
235 ComputeSquaredDistance,
236 Debug,
237 Deserialize,
238 MallocSizeOf,
239 PartialEq,
240 Serialize,
241 SpecifiedValueInfo,
242 ToAnimatedValue,
243 ToComputedValue,
244 ToResolvedValue,
245 ToShmem,
246)]
247#[css(function = "inset")]
248#[repr(C)]
249pub struct GenericInsetRect<LengthPercentage> {
250 pub rect: Rect<LengthPercentage>,
251 #[shmem(field_bound)]
252 #[animation(field_bound)]
253 pub round: GenericBorderRadius<NonNegative<LengthPercentage>>,
254}
255
256pub use self::GenericInsetRect as InsetRect;
257
258#[allow(missing_docs)]
260#[derive(
261 Animate,
262 Clone,
263 ComputeSquaredDistance,
264 Copy,
265 Debug,
266 Deserialize,
267 MallocSizeOf,
268 PartialEq,
269 Serialize,
270 SpecifiedValueInfo,
271 ToAnimatedValue,
272 ToComputedValue,
273 ToResolvedValue,
274 ToShmem,
275)]
276#[css(function)]
277#[repr(C)]
278pub struct Circle<LengthPercentage> {
279 pub position: GenericPositionOrAuto<ShapePosition<LengthPercentage>>,
280 #[animation(field_bound)]
281 pub radius: GenericShapeRadius<LengthPercentage>,
282}
283
284#[allow(missing_docs)]
286#[derive(
287 Animate,
288 Clone,
289 ComputeSquaredDistance,
290 Copy,
291 Debug,
292 Deserialize,
293 MallocSizeOf,
294 PartialEq,
295 Serialize,
296 SpecifiedValueInfo,
297 ToAnimatedValue,
298 ToComputedValue,
299 ToResolvedValue,
300 ToShmem,
301)]
302#[css(function)]
303#[repr(C)]
304pub struct Ellipse<LengthPercentage> {
305 pub position: GenericPositionOrAuto<ShapePosition<LengthPercentage>>,
306 #[animation(field_bound)]
307 pub semiaxis_x: GenericShapeRadius<LengthPercentage>,
308 #[animation(field_bound)]
309 pub semiaxis_y: GenericShapeRadius<LengthPercentage>,
310}
311
312#[allow(missing_docs)]
314#[derive(
315 Animate,
316 Clone,
317 ComputeSquaredDistance,
318 Copy,
319 Debug,
320 Deserialize,
321 MallocSizeOf,
322 Parse,
323 PartialEq,
324 Serialize,
325 SpecifiedValueInfo,
326 ToAnimatedValue,
327 ToComputedValue,
328 ToCss,
329 ToResolvedValue,
330 ToShmem,
331)]
332#[repr(C, u8)]
333pub enum GenericShapeRadius<LengthPercentage> {
334 Length(
335 #[animation(field_bound)]
336 #[parse(field_bound)]
337 NonNegative<LengthPercentage>,
338 ),
339 #[animation(error)]
340 ClosestSide,
341 #[animation(error)]
342 FarthestSide,
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(#[css(field_bound)] Shape<Angle, Position, LengthPercentage>),
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<LengthPercentage> ToCss for Circle<LengthPercentage>
520where
521 LengthPercentage: ToCss + PartialEq,
522 ShapePosition<LengthPercentage>: 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<LengthPercentage> ToCss for Ellipse<LengthPercentage>
549where
550 LengthPercentage: ToCss + PartialEq,
551 ShapePosition<LengthPercentage>: 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 pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, Position, LengthPercentage>>,
653}
654
655impl<Angle, Position, LengthPercentage> Shape<Angle, Position, LengthPercentage> {
656 #[inline]
658 pub fn commands(&self) -> &[GenericShapeCommand<Angle, Position, LengthPercentage>] {
659 &self.commands
660 }
661}
662
663impl<Angle, Position, LengthPercentage> Animate for Shape<Angle, Position, LengthPercentage>
664where
665 Angle: Animate,
666 Position: Animate,
667 LengthPercentage: Animate,
668{
669 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
670 if self.fill != other.fill {
671 return Err(());
672 }
673 let commands =
674 lists::by_computed_value::animate(&self.commands, &other.commands, procedure)?;
675 Ok(Self {
676 fill: self.fill,
677 commands,
678 })
679 }
680}
681
682impl<Angle, Position, LengthPercentage> ComputeSquaredDistance
683 for Shape<Angle, Position, LengthPercentage>
684where
685 Angle: ComputeSquaredDistance,
686 Position: ComputeSquaredDistance,
687 LengthPercentage: ComputeSquaredDistance,
688{
689 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
690 if self.fill != other.fill {
691 return Err(());
692 }
693 lists::by_computed_value::squared_distance(&self.commands, &other.commands)
694 }
695}
696
697impl<Angle, Position, LengthPercentage> ToCss for Shape<Angle, Position, LengthPercentage>
698where
699 Angle: ToCss + Zero,
700 Position: ToCss,
701 LengthPercentage: PartialEq + ToCss,
702{
703 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
704 where
705 W: Write,
706 {
707 use style_traits::values::SequenceWriter;
708
709 debug_assert!(self.commands.len() > 1);
711
712 dest.write_str("shape(")?;
713 if !is_default(&self.fill) {
714 self.fill.to_css(dest)?;
715 dest.write_char(' ')?;
716 }
717 dest.write_str("from ")?;
718 match &self.commands[0] {
719 ShapeCommand::Move {
720 point: CommandEndPoint::ToPosition(pos),
721 } => pos.to_css(dest)?,
722 ShapeCommand::Move {
723 point: CommandEndPoint::ByCoordinate(coord),
724 } => coord.to_css(dest)?,
725 _ => unreachable!("The first command must be move"),
726 }
727 dest.write_str(", ")?;
728 {
729 let mut writer = SequenceWriter::new(dest, ", ");
730 for command in self.commands.iter().skip(1) {
731 writer.item(command)?;
732 }
733 }
734 dest.write_char(')')
735 }
736}
737
738#[derive(
743 Animate,
744 Clone,
745 ComputeSquaredDistance,
746 Copy,
747 Debug,
748 Deserialize,
749 MallocSizeOf,
750 PartialEq,
751 Serialize,
752 SpecifiedValueInfo,
753 ToAnimatedValue,
754 ToAnimatedZero,
755 ToComputedValue,
756 ToResolvedValue,
757 ToShmem,
758)]
759#[allow(missing_docs)]
760#[repr(C, u8)]
761pub enum GenericShapeCommand<Angle, Position, LengthPercentage> {
762 Move {
764 point: CommandEndPoint<Position, LengthPercentage>,
765 },
766 Line {
768 point: CommandEndPoint<Position, LengthPercentage>,
769 },
770 HLine { by_to: ByTo, x: LengthPercentage },
772 VLine { by_to: ByTo, y: LengthPercentage },
774 CubicCurve {
776 point: CommandEndPoint<Position, LengthPercentage>,
777 control1: ControlPoint<Position, LengthPercentage>,
778 control2: ControlPoint<Position, LengthPercentage>,
779 },
780 QuadCurve {
782 point: CommandEndPoint<Position, LengthPercentage>,
783 control1: ControlPoint<Position, LengthPercentage>,
784 },
785 SmoothCubic {
787 point: CommandEndPoint<Position, LengthPercentage>,
788 control2: ControlPoint<Position, LengthPercentage>,
789 },
790 SmoothQuad {
792 point: CommandEndPoint<Position, LengthPercentage>,
793 },
794 Arc {
796 point: CommandEndPoint<Position, LengthPercentage>,
797 radii: ArcRadii<LengthPercentage>,
798 arc_sweep: ArcSweep,
799 arc_size: ArcSize,
800 rotate: Angle,
801 },
802 Close,
804}
805
806pub use self::GenericShapeCommand as ShapeCommand;
807
808impl<Angle, Position, LengthPercentage> ToCss for ShapeCommand<Angle, Position, LengthPercentage>
809where
810 Angle: ToCss + Zero,
811 Position: ToCss,
812 LengthPercentage: PartialEq + ToCss,
813{
814 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
815 where
816 W: fmt::Write,
817 {
818 use self::ShapeCommand::*;
819 match *self {
820 Move { ref point } => {
821 dest.write_str("move ")?;
822 point.to_css(dest)
823 },
824 Line { ref point } => {
825 dest.write_str("line ")?;
826 point.to_css(dest)
827 },
828 HLine { by_to, ref x } => {
829 dest.write_str("hline ")?;
830 by_to.to_css(dest)?;
831 dest.write_char(' ')?;
832 x.to_css(dest)
833 },
834 VLine { by_to, ref y } => {
835 dest.write_str("vline ")?;
836 by_to.to_css(dest)?;
837 dest.write_char(' ')?;
838 y.to_css(dest)
839 },
840 CubicCurve {
841 ref point,
842 ref control1,
843 ref control2,
844 } => {
845 dest.write_str("curve ")?;
846 point.to_css(dest)?;
847 dest.write_str(" with ")?;
848 control1.to_css(dest, point.is_abs())?;
849 dest.write_char(' ')?;
850 dest.write_char('/')?;
851 dest.write_char(' ')?;
852 control2.to_css(dest, point.is_abs())
853 },
854 QuadCurve {
855 ref point,
856 ref control1,
857 } => {
858 dest.write_str("curve ")?;
859 point.to_css(dest)?;
860 dest.write_str(" with ")?;
861 control1.to_css(dest, point.is_abs())
862 },
863 SmoothCubic {
864 ref point,
865 ref control2,
866 } => {
867 dest.write_str("smooth ")?;
868 point.to_css(dest)?;
869 dest.write_str(" with ")?;
870 control2.to_css(dest, point.is_abs())
871 },
872 SmoothQuad { ref point } => {
873 dest.write_str("smooth ")?;
874 point.to_css(dest)
875 },
876 Arc {
877 ref point,
878 ref radii,
879 arc_sweep,
880 arc_size,
881 ref rotate,
882 } => {
883 dest.write_str("arc ")?;
884 point.to_css(dest)?;
885 dest.write_str(" of ")?;
886 radii.to_css(dest)?;
887
888 if matches!(arc_sweep, ArcSweep::Cw) {
889 dest.write_str(" cw")?;
890 }
891
892 if matches!(arc_size, ArcSize::Large) {
893 dest.write_str(" large")?;
894 }
895
896 if !rotate.is_zero() {
897 dest.write_str(" rotate ")?;
898 rotate.to_css(dest)?;
899 }
900 Ok(())
901 },
902 Close => dest.write_str("close"),
903 }
904 }
905}
906
907#[derive(
910 Animate,
911 Clone,
912 ComputeSquaredDistance,
913 Copy,
914 Debug,
915 Deserialize,
916 MallocSizeOf,
917 Parse,
918 PartialEq,
919 Serialize,
920 SpecifiedValueInfo,
921 ToAnimatedValue,
922 ToAnimatedZero,
923 ToComputedValue,
924 ToCss,
925 ToResolvedValue,
926 ToShmem,
927)]
928#[repr(u8)]
929pub enum ByTo {
930 By,
932 To,
934}
935
936impl ByTo {
937 #[inline]
939 pub fn is_abs(&self) -> bool {
940 matches!(self, ByTo::To)
941 }
942
943 #[inline]
945 pub fn new(is_abs: bool) -> Self {
946 if is_abs {
947 Self::To
948 } else {
949 Self::By
950 }
951 }
952}
953
954#[allow(missing_docs)]
958#[derive(
959 Animate,
960 Clone,
961 Copy,
962 ComputeSquaredDistance,
963 Debug,
964 Deserialize,
965 MallocSizeOf,
966 PartialEq,
967 Serialize,
968 SpecifiedValueInfo,
969 ToAnimatedValue,
970 ToAnimatedZero,
971 ToComputedValue,
972 ToResolvedValue,
973 ToShmem,
974)]
975#[repr(C, u8)]
976pub enum CommandEndPoint<Position, LengthPercentage> {
977 ToPosition(Position),
978 ByCoordinate(CoordinatePair<LengthPercentage>),
979}
980
981impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> {
982 #[inline]
984 pub fn is_abs(&self) -> bool {
985 matches!(self, CommandEndPoint::ToPosition(_))
986 }
987}
988
989impl<Position, LengthPercentage> CommandEndPoint<Position, LengthPercentage> {
990 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
991 where
992 W: Write,
993 Position: ToCss,
994 LengthPercentage: ToCss,
995 {
996 match self {
997 CommandEndPoint::ToPosition(pos) => {
998 dest.write_str("to ")?;
999 pos.to_css(dest)
1000 },
1001 CommandEndPoint::ByCoordinate(coord) => {
1002 dest.write_str("by ")?;
1003 coord.to_css(dest)
1004 },
1005 }
1006 }
1007}
1008
1009#[allow(missing_docs)]
1014#[derive(
1015 AddAssign,
1016 Animate,
1017 Clone,
1018 ComputeSquaredDistance,
1019 Copy,
1020 Debug,
1021 Deserialize,
1022 MallocSizeOf,
1023 PartialEq,
1024 Serialize,
1025 SpecifiedValueInfo,
1026 ToAnimatedValue,
1027 ToAnimatedZero,
1028 ToComputedValue,
1029 ToCss,
1030 ToResolvedValue,
1031 ToShmem,
1032)]
1033#[repr(C)]
1034pub struct CoordinatePair<LengthPercentage> {
1035 pub x: LengthPercentage,
1036 pub y: LengthPercentage,
1037}
1038
1039impl<LengthPercentage> CoordinatePair<LengthPercentage> {
1040 #[inline]
1042 pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self {
1043 Self { x, y }
1044 }
1045}
1046
1047#[allow(missing_docs)]
1051#[derive(
1052 Animate,
1053 Clone,
1054 Copy,
1055 ComputeSquaredDistance,
1056 Debug,
1057 Deserialize,
1058 MallocSizeOf,
1059 PartialEq,
1060 Serialize,
1061 SpecifiedValueInfo,
1062 ToAnimatedValue,
1063 ToAnimatedZero,
1064 ToComputedValue,
1065 ToResolvedValue,
1066 ToShmem,
1067)]
1068#[repr(C, u8)]
1069pub enum ControlPoint<Position, LengthPercentage> {
1070 Absolute(Position),
1071 Relative(RelativeControlPoint<LengthPercentage>),
1072}
1073
1074impl<Position, LengthPercentage> ControlPoint<Position, LengthPercentage> {
1075 pub fn to_css<W>(&self, dest: &mut CssWriter<W>, is_endpoint_abs: bool) -> fmt::Result
1077 where
1078 W: Write,
1079 Position: ToCss,
1080 LengthPercentage: ToCss,
1081 {
1082 match self {
1083 ControlPoint::Absolute(pos) => pos.to_css(dest),
1084 ControlPoint::Relative(point) => point.to_css(dest, is_endpoint_abs),
1085 }
1086 }
1087}
1088
1089#[allow(missing_docs)]
1093#[derive(
1094 Animate,
1095 Clone,
1096 Copy,
1097 Debug,
1098 Deserialize,
1099 MallocSizeOf,
1100 PartialEq,
1101 Serialize,
1102 SpecifiedValueInfo,
1103 ToAnimatedValue,
1104 ToAnimatedZero,
1105 ToComputedValue,
1106 ToResolvedValue,
1107 ToShmem,
1108)]
1109#[repr(C)]
1110pub struct RelativeControlPoint<LengthPercentage> {
1111 pub coord: CoordinatePair<LengthPercentage>,
1112 pub reference: ControlReference,
1113}
1114
1115impl<LengthPercentage: ToCss> RelativeControlPoint<LengthPercentage> {
1116 fn to_css<W>(&self, dest: &mut CssWriter<W>, is_endpoint_abs: bool) -> fmt::Result
1117 where
1118 W: Write,
1119 {
1120 self.coord.to_css(dest)?;
1121 let should_omit_reference = match self.reference {
1122 ControlReference::None => true,
1123 ControlReference::Start => !is_endpoint_abs,
1124 ControlReference::Origin => is_endpoint_abs,
1125 ControlReference::End => false,
1126 };
1127 if !should_omit_reference {
1128 dest.write_str(" from ")?;
1129 self.reference.to_css(dest)?;
1130 }
1131 Ok(())
1132 }
1133}
1134
1135impl<LengthPercentage: ComputeSquaredDistance> ComputeSquaredDistance
1136 for RelativeControlPoint<LengthPercentage>
1137{
1138 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1139 self.coord.compute_squared_distance(&other.coord)
1140 }
1141}
1142
1143#[allow(missing_docs)]
1150#[derive(
1151 Animate,
1152 Clone,
1153 Copy,
1154 Debug,
1155 Deserialize,
1156 Eq,
1157 MallocSizeOf,
1158 PartialEq,
1159 Parse,
1160 Serialize,
1161 SpecifiedValueInfo,
1162 ToAnimatedValue,
1163 ToAnimatedZero,
1164 ToComputedValue,
1165 ToCss,
1166 ToResolvedValue,
1167 ToShmem,
1168)]
1169#[repr(C)]
1170pub enum ControlReference {
1171 #[css(skip)]
1172 None,
1173 Start,
1174 End,
1175 Origin,
1176}
1177
1178#[allow(missing_docs)]
1185#[derive(
1186 Animate,
1187 Clone,
1188 ComputeSquaredDistance,
1189 Copy,
1190 Debug,
1191 Deserialize,
1192 MallocSizeOf,
1193 PartialEq,
1194 Serialize,
1195 SpecifiedValueInfo,
1196 ToAnimatedValue,
1197 ToAnimatedZero,
1198 ToComputedValue,
1199 ToCss,
1200 ToResolvedValue,
1201 ToShmem,
1202)]
1203#[repr(C)]
1204pub struct ArcRadii<LengthPercentage> {
1205 pub rx: LengthPercentage,
1206 pub ry: Optional<LengthPercentage>,
1207}
1208
1209#[derive(
1213 Clone,
1214 Copy,
1215 Debug,
1216 Deserialize,
1217 FromPrimitive,
1218 MallocSizeOf,
1219 Parse,
1220 PartialEq,
1221 Serialize,
1222 SpecifiedValueInfo,
1223 ToAnimatedValue,
1224 ToAnimatedZero,
1225 ToComputedValue,
1226 ToCss,
1227 ToResolvedValue,
1228 ToShmem,
1229)]
1230#[repr(u8)]
1231pub enum ArcSweep {
1232 Ccw = 0,
1234 Cw = 1,
1236}
1237
1238impl Animate for ArcSweep {
1239 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1240 use num_traits::FromPrimitive;
1241 (*self as i32)
1244 .animate(&(*other as i32), procedure)
1245 .map(|v| ArcSweep::from_u8((v > 0) as u8).unwrap_or(ArcSweep::Ccw))
1246 }
1247}
1248
1249impl ComputeSquaredDistance for ArcSweep {
1250 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1251 (*self as i32).compute_squared_distance(&(*other as i32))
1252 }
1253}
1254
1255#[derive(
1259 Clone,
1260 Copy,
1261 Debug,
1262 Deserialize,
1263 FromPrimitive,
1264 MallocSizeOf,
1265 Parse,
1266 PartialEq,
1267 Serialize,
1268 SpecifiedValueInfo,
1269 ToAnimatedValue,
1270 ToAnimatedZero,
1271 ToComputedValue,
1272 ToCss,
1273 ToResolvedValue,
1274 ToShmem,
1275)]
1276#[repr(u8)]
1277pub enum ArcSize {
1278 Small = 0,
1280 Large = 1,
1282}
1283
1284impl Animate for ArcSize {
1285 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1286 use num_traits::FromPrimitive;
1287 (*self as i32)
1290 .animate(&(*other as i32), procedure)
1291 .map(|v| ArcSize::from_u8((v > 0) as u8).unwrap_or(ArcSize::Small))
1292 }
1293}
1294
1295impl ComputeSquaredDistance for ArcSize {
1296 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1297 (*self as i32).compute_squared_distance(&(*other as i32))
1298 }
1299}