1use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero};
9use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
10use crate::values::generics::border::GenericBorderRadius;
11use crate::values::generics::position::{GenericPosition, GenericPositionOrAuto};
12use crate::values::generics::rect::Rect;
13use crate::values::specified::svg_path::{PathCommand, SVGPathData};
14use crate::Zero;
15use std::fmt::{self, Write};
16use std::ops::AddAssign;
17use style_traits::{CssWriter, ToCss};
18
19pub type ShapePosition<LengthPercentage> = GenericPosition<LengthPercentage, LengthPercentage>;
22
23#[allow(missing_docs)]
25#[derive(
26 Animate,
27 Clone,
28 ComputeSquaredDistance,
29 Copy,
30 Debug,
31 MallocSizeOf,
32 PartialEq,
33 Parse,
34 SpecifiedValueInfo,
35 ToAnimatedValue,
36 ToComputedValue,
37 ToCss,
38 ToResolvedValue,
39 ToShmem,
40 ToTyped,
41)]
42#[repr(u8)]
43#[typed_value(derive_fields)]
44pub enum ShapeGeometryBox {
45 #[css(skip)]
52 ElementDependent,
53 FillBox,
54 StrokeBox,
55 ViewBox,
56 ShapeBox(ShapeBox),
57}
58
59impl Default for ShapeGeometryBox {
60 fn default() -> Self {
61 Self::ElementDependent
62 }
63}
64
65#[inline]
67fn is_default_box_for_clip_path(b: &ShapeGeometryBox) -> bool {
68 matches!(b, ShapeGeometryBox::ElementDependent)
71 || matches!(b, ShapeGeometryBox::ShapeBox(ShapeBox::BorderBox))
72}
73
74#[allow(missing_docs)]
76#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
77#[derive(
78 Animate,
79 Clone,
80 Copy,
81 ComputeSquaredDistance,
82 Debug,
83 Eq,
84 MallocSizeOf,
85 Parse,
86 PartialEq,
87 SpecifiedValueInfo,
88 ToAnimatedValue,
89 ToComputedValue,
90 ToCss,
91 ToResolvedValue,
92 ToShmem,
93 ToTyped,
94)]
95#[repr(u8)]
96pub enum ShapeBox {
97 MarginBox,
98 BorderBox,
99 PaddingBox,
100 ContentBox,
101}
102
103impl Default for ShapeBox {
104 fn default() -> Self {
105 ShapeBox::MarginBox
106 }
107}
108
109#[allow(missing_docs)]
111#[derive(
112 Animate,
113 Clone,
114 ComputeSquaredDistance,
115 Debug,
116 MallocSizeOf,
117 PartialEq,
118 SpecifiedValueInfo,
119 ToAnimatedValue,
120 ToComputedValue,
121 ToCss,
122 ToResolvedValue,
123 ToShmem,
124 ToTyped,
125)]
126#[animation(no_bound(U))]
127#[repr(u8)]
128#[typed_value(derive_fields)]
129pub enum GenericClipPath<BasicShape, U> {
130 #[animation(error)]
131 None,
132 #[animation(error)]
133 #[typed_value(todo)]
137 Url(U),
138 #[typed_value(skip)]
139 Shape(
140 Box<BasicShape>,
141 #[css(skip_if = "is_default_box_for_clip_path")] ShapeGeometryBox,
142 ),
143 #[animation(error)]
144 Box(ShapeGeometryBox),
145}
146
147pub use self::GenericClipPath as ClipPath;
148
149#[allow(missing_docs)]
151#[derive(
152 Animate,
153 Clone,
154 ComputeSquaredDistance,
155 Debug,
156 MallocSizeOf,
157 PartialEq,
158 SpecifiedValueInfo,
159 ToAnimatedValue,
160 ToComputedValue,
161 ToCss,
162 ToResolvedValue,
163 ToShmem,
164 ToTyped,
165)]
166#[animation(no_bound(I))]
167#[repr(u8)]
168pub enum GenericShapeOutside<BasicShape, I> {
169 #[animation(error)]
170 None,
171 #[animation(error)]
172 Image(I),
173 Shape(Box<BasicShape>, #[css(skip_if = "is_default")] ShapeBox),
174 #[animation(error)]
175 Box(ShapeBox),
176}
177
178pub use self::GenericShapeOutside as ShapeOutside;
179
180#[derive(
184 Animate,
185 Clone,
186 ComputeSquaredDistance,
187 Debug,
188 Deserialize,
189 MallocSizeOf,
190 PartialEq,
191 Serialize,
192 SpecifiedValueInfo,
193 ToAnimatedValue,
194 ToComputedValue,
195 ToCss,
196 ToResolvedValue,
197 ToShmem,
198)]
199#[repr(C, u8)]
200pub enum GenericBasicShape<
201 Angle,
202 Position,
203 LengthPercentage,
204 NonNegativeLengthPercentage,
205 BasicShapeRect,
206> {
207 Rect(BasicShapeRect),
209 Circle(
211 #[css(field_bound)]
212 #[shmem(field_bound)]
213 Circle<Position, NonNegativeLengthPercentage>,
214 ),
215 Ellipse(
217 #[css(field_bound)]
218 #[shmem(field_bound)]
219 Ellipse<Position, NonNegativeLengthPercentage>,
220 ),
221 Polygon(GenericPolygon<LengthPercentage>),
223 PathOrShape(
225 #[animation(field_bound)]
226 #[css(field_bound)]
227 GenericPathOrShapeFunction<Angle, 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, NonNegativeLengthPercentage> {
253 pub rect: Rect<LengthPercentage>,
254 #[shmem(field_bound)]
255 pub round: GenericBorderRadius<NonNegativeLengthPercentage>,
256}
257
258pub use self::GenericInsetRect as InsetRect;
259
260#[allow(missing_docs)]
262#[derive(
263 Animate,
264 Clone,
265 ComputeSquaredDistance,
266 Copy,
267 Debug,
268 Deserialize,
269 MallocSizeOf,
270 PartialEq,
271 Serialize,
272 SpecifiedValueInfo,
273 ToAnimatedValue,
274 ToComputedValue,
275 ToResolvedValue,
276 ToShmem,
277)]
278#[css(function)]
279#[repr(C)]
280pub struct Circle<Position, NonNegativeLengthPercentage> {
281 pub position: GenericPositionOrAuto<Position>,
282 pub radius: GenericShapeRadius<NonNegativeLengthPercentage>,
283}
284
285#[allow(missing_docs)]
287#[derive(
288 Animate,
289 Clone,
290 ComputeSquaredDistance,
291 Copy,
292 Debug,
293 Deserialize,
294 MallocSizeOf,
295 PartialEq,
296 Serialize,
297 SpecifiedValueInfo,
298 ToAnimatedValue,
299 ToComputedValue,
300 ToResolvedValue,
301 ToShmem,
302)]
303#[css(function)]
304#[repr(C)]
305pub struct Ellipse<Position, NonNegativeLengthPercentage> {
306 pub position: GenericPositionOrAuto<Position>,
307 pub semiaxis_x: GenericShapeRadius<NonNegativeLengthPercentage>,
308 pub semiaxis_y: GenericShapeRadius<NonNegativeLengthPercentage>,
309}
310
311#[allow(missing_docs)]
313#[derive(
314 Animate,
315 Clone,
316 ComputeSquaredDistance,
317 Copy,
318 Debug,
319 Deserialize,
320 MallocSizeOf,
321 Parse,
322 PartialEq,
323 Serialize,
324 SpecifiedValueInfo,
325 ToAnimatedValue,
326 ToComputedValue,
327 ToCss,
328 ToResolvedValue,
329 ToShmem,
330)]
331#[repr(C, u8)]
332pub enum GenericShapeRadius<NonNegativeLengthPercentage> {
333 Length(NonNegativeLengthPercentage),
334 #[animation(error)]
335 ClosestSide,
336 #[animation(error)]
337 FarthestSide,
338}
339
340pub use self::GenericShapeRadius as ShapeRadius;
341
342#[derive(
346 Clone,
347 Debug,
348 Deserialize,
349 MallocSizeOf,
350 PartialEq,
351 Serialize,
352 SpecifiedValueInfo,
353 ToAnimatedValue,
354 ToComputedValue,
355 ToCss,
356 ToResolvedValue,
357 ToShmem,
358)]
359#[css(comma, function = "polygon")]
360#[repr(C)]
361pub struct GenericPolygon<LengthPercentage> {
362 #[css(skip_if = "is_default")]
364 pub fill: FillRule,
365 #[css(iterable)]
367 pub coordinates: crate::OwnedSlice<PolygonCoord<LengthPercentage>>,
368}
369
370pub use self::GenericPolygon as Polygon;
371
372#[derive(
374 Animate,
375 Clone,
376 ComputeSquaredDistance,
377 Debug,
378 Deserialize,
379 MallocSizeOf,
380 PartialEq,
381 Serialize,
382 SpecifiedValueInfo,
383 ToAnimatedValue,
384 ToComputedValue,
385 ToCss,
386 ToResolvedValue,
387 ToShmem,
388)]
389#[repr(C)]
390pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercentage);
391
392#[derive(
394 Clone,
395 ComputeSquaredDistance,
396 Debug,
397 Deserialize,
398 MallocSizeOf,
399 PartialEq,
400 Serialize,
401 SpecifiedValueInfo,
402 ToAnimatedValue,
403 ToComputedValue,
404 ToCss,
405 ToResolvedValue,
406 ToShmem,
407)]
408#[repr(C, u8)]
409pub enum GenericPathOrShapeFunction<Angle, LengthPercentage> {
410 Path(Path),
412 Shape(#[css(field_bound)] Shape<Angle, LengthPercentage>),
414}
415
416#[allow(missing_docs)]
421#[derive(
422 Animate,
423 Clone,
424 ComputeSquaredDistance,
425 Copy,
426 Debug,
427 Deserialize,
428 Eq,
429 MallocSizeOf,
430 Parse,
431 PartialEq,
432 Serialize,
433 SpecifiedValueInfo,
434 ToAnimatedValue,
435 ToComputedValue,
436 ToCss,
437 ToResolvedValue,
438 ToShmem,
439 ToTyped,
440)]
441#[repr(u8)]
442pub enum FillRule {
443 Nonzero,
444 Evenodd,
445}
446
447#[derive(
451 Animate,
452 Clone,
453 ComputeSquaredDistance,
454 Debug,
455 Deserialize,
456 MallocSizeOf,
457 PartialEq,
458 Serialize,
459 SpecifiedValueInfo,
460 ToAnimatedValue,
461 ToComputedValue,
462 ToCss,
463 ToResolvedValue,
464 ToShmem,
465)]
466#[css(comma, function = "path")]
467#[repr(C)]
468pub struct Path {
469 #[css(skip_if = "is_default")]
471 pub fill: FillRule,
472 pub path: SVGPathData,
474}
475
476impl Path {
477 #[inline]
479 pub fn commands(&self) -> &[PathCommand] {
480 self.path.commands()
481 }
482}
483
484impl<B, U> ToAnimatedZero for ClipPath<B, U> {
485 fn to_animated_zero(&self) -> Result<Self, ()> {
486 Err(())
487 }
488}
489
490impl<B, U> ToAnimatedZero for ShapeOutside<B, U> {
491 fn to_animated_zero(&self) -> Result<Self, ()> {
492 Err(())
493 }
494}
495
496impl<Length, NonNegativeLength> ToCss for InsetRect<Length, NonNegativeLength>
497where
498 Length: ToCss + PartialEq,
499 NonNegativeLength: ToCss + PartialEq + Zero,
500{
501 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
502 where
503 W: Write,
504 {
505 dest.write_str("inset(")?;
506 self.rect.to_css(dest)?;
507 if !self.round.is_zero() {
508 dest.write_str(" round ")?;
509 self.round.to_css(dest)?;
510 }
511 dest.write_char(')')
512 }
513}
514
515impl<Position, NonNegativeLengthPercentage> ToCss for Circle<Position, NonNegativeLengthPercentage>
516where
517 Position: ToCss,
518 NonNegativeLengthPercentage: ToCss + PartialEq,
519{
520 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
521 where
522 W: Write,
523 {
524 let has_radius = self.radius != Default::default();
525
526 dest.write_str("circle(")?;
527 if has_radius {
528 self.radius.to_css(dest)?;
529 }
530
531 if !matches!(self.position, GenericPositionOrAuto::Auto) {
534 if has_radius {
535 dest.write_char(' ')?;
536 }
537 dest.write_str("at ")?;
538 self.position.to_css(dest)?;
539 }
540 dest.write_char(')')
541 }
542}
543
544impl<Position, NonNegativeLengthPercentage> ToCss for Ellipse<Position, NonNegativeLengthPercentage>
545where
546 Position: ToCss,
547 NonNegativeLengthPercentage: ToCss + PartialEq,
548{
549 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
550 where
551 W: Write,
552 {
553 let has_radii =
554 self.semiaxis_x != Default::default() || self.semiaxis_y != Default::default();
555
556 dest.write_str("ellipse(")?;
557 if has_radii {
558 self.semiaxis_x.to_css(dest)?;
559 dest.write_char(' ')?;
560 self.semiaxis_y.to_css(dest)?;
561 }
562
563 if !matches!(self.position, GenericPositionOrAuto::Auto) {
566 if has_radii {
567 dest.write_char(' ')?;
568 }
569 dest.write_str("at ")?;
570 self.position.to_css(dest)?;
571 }
572 dest.write_char(')')
573 }
574}
575
576impl<L> Default for ShapeRadius<L> {
577 #[inline]
578 fn default() -> Self {
579 ShapeRadius::ClosestSide
580 }
581}
582
583impl<L> Animate for Polygon<L>
584where
585 L: Animate,
586{
587 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
588 if self.fill != other.fill {
589 return Err(());
590 }
591 let coordinates =
592 lists::by_computed_value::animate(&self.coordinates, &other.coordinates, procedure)?;
593 Ok(Polygon {
594 fill: self.fill,
595 coordinates,
596 })
597 }
598}
599
600impl<L> ComputeSquaredDistance for Polygon<L>
601where
602 L: ComputeSquaredDistance,
603{
604 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
605 if self.fill != other.fill {
606 return Err(());
607 }
608 lists::by_computed_value::squared_distance(&self.coordinates, &other.coordinates)
609 }
610}
611
612impl Default for FillRule {
613 #[inline]
614 fn default() -> Self {
615 FillRule::Nonzero
616 }
617}
618
619#[inline]
620fn is_default<T: Default + PartialEq>(fill: &T) -> bool {
621 *fill == Default::default()
622}
623
624#[derive(
629 Clone,
630 Debug,
631 Deserialize,
632 MallocSizeOf,
633 PartialEq,
634 Serialize,
635 SpecifiedValueInfo,
636 ToAnimatedValue,
637 ToComputedValue,
638 ToResolvedValue,
639 ToShmem,
640)]
641#[repr(C)]
642pub struct Shape<Angle, LengthPercentage> {
643 pub fill: FillRule,
645 pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, LengthPercentage>>,
649}
650
651impl<Angle, LengthPercentage> Shape<Angle, LengthPercentage> {
652 #[inline]
654 pub fn commands(&self) -> &[GenericShapeCommand<Angle, LengthPercentage>] {
655 &self.commands
656 }
657}
658
659impl<Angle, LengthPercentage> Animate for Shape<Angle, LengthPercentage>
660where
661 Angle: Animate,
662 LengthPercentage: Animate,
663{
664 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
665 if self.fill != other.fill {
666 return Err(());
667 }
668 let commands =
669 lists::by_computed_value::animate(&self.commands, &other.commands, procedure)?;
670 Ok(Self {
671 fill: self.fill,
672 commands,
673 })
674 }
675}
676
677impl<Angle, LengthPercentage> ComputeSquaredDistance for Shape<Angle, LengthPercentage>
678where
679 Angle: ComputeSquaredDistance,
680 LengthPercentage: ComputeSquaredDistance,
681{
682 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
683 if self.fill != other.fill {
684 return Err(());
685 }
686 lists::by_computed_value::squared_distance(&self.commands, &other.commands)
687 }
688}
689
690impl<Angle, LengthPercentage> ToCss for Shape<Angle, LengthPercentage>
691where
692 Angle: ToCss + Zero,
693 LengthPercentage: PartialEq + ToCss,
694{
695 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
696 where
697 W: Write,
698 {
699 use style_traits::values::SequenceWriter;
700
701 debug_assert!(self.commands.len() > 1);
703
704 dest.write_str("shape(")?;
705 if !is_default(&self.fill) {
706 self.fill.to_css(dest)?;
707 dest.write_char(' ')?;
708 }
709 dest.write_str("from ")?;
710 match &self.commands[0] {
711 ShapeCommand::Move {
712 point: CommandEndPoint::ToPosition(pos),
713 } => {
714 pos.horizontal.to_css(dest)?;
715 dest.write_char(' ')?;
716 pos.vertical.to_css(dest)?
717 },
718 ShapeCommand::Move {
719 point: CommandEndPoint::ByCoordinate(coord),
720 } => coord.to_css(dest)?,
721 _ => unreachable!("The first command must be move"),
722 }
723 dest.write_str(", ")?;
724 {
725 let mut writer = SequenceWriter::new(dest, ", ");
726 for command in self.commands.iter().skip(1) {
727 writer.item(command)?;
728 }
729 }
730 dest.write_char(')')
731 }
732}
733
734#[derive(
739 Animate,
740 Clone,
741 ComputeSquaredDistance,
742 Copy,
743 Debug,
744 Deserialize,
745 MallocSizeOf,
746 PartialEq,
747 Serialize,
748 SpecifiedValueInfo,
749 ToAnimatedValue,
750 ToAnimatedZero,
751 ToComputedValue,
752 ToResolvedValue,
753 ToShmem,
754)]
755#[allow(missing_docs)]
756#[repr(C, u8)]
757pub enum GenericShapeCommand<Angle, LengthPercentage> {
758 Move {
760 point: CommandEndPoint<LengthPercentage>,
761 },
762 Line {
764 point: CommandEndPoint<LengthPercentage>,
765 },
766 HLine { by_to: ByTo, x: LengthPercentage },
768 VLine { by_to: ByTo, y: LengthPercentage },
770 CubicCurve {
772 point: CommandEndPoint<LengthPercentage>,
773 control1: CoordinatePair<LengthPercentage>,
774 control2: CoordinatePair<LengthPercentage>,
775 },
776 QuadCurve {
778 point: CommandEndPoint<LengthPercentage>,
779 control1: CoordinatePair<LengthPercentage>,
780 },
781 SmoothCubic {
783 point: CommandEndPoint<LengthPercentage>,
784 control2: CoordinatePair<LengthPercentage>,
785 },
786 SmoothQuad {
788 point: CommandEndPoint<LengthPercentage>,
789 },
790 Arc {
792 point: CommandEndPoint<LengthPercentage>,
793 radii: CoordinatePair<LengthPercentage>,
794 arc_sweep: ArcSweep,
795 arc_size: ArcSize,
796 rotate: Angle,
797 },
798 Close,
800}
801
802pub use self::GenericShapeCommand as ShapeCommand;
803
804impl<Angle, LengthPercentage> ToCss for ShapeCommand<Angle, LengthPercentage>
805where
806 Angle: ToCss + Zero,
807 LengthPercentage: PartialEq + ToCss,
808{
809 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
810 where
811 W: fmt::Write,
812 {
813 use self::ShapeCommand::*;
814 match *self {
815 Move { ref point } => {
816 dest.write_str("move ")?;
817 point.to_css(dest)
818 },
819 Line { ref point } => {
820 dest.write_str("line ")?;
821 point.to_css(dest)
822 },
823 HLine { by_to, ref x } => {
824 dest.write_str("hline ")?;
825 by_to.to_css(dest)?;
826 dest.write_char(' ')?;
827 x.to_css(dest)
828 },
829 VLine { by_to, ref y } => {
830 dest.write_str("vline ")?;
831 by_to.to_css(dest)?;
832 dest.write_char(' ')?;
833 y.to_css(dest)
834 },
835 CubicCurve {
836 ref point,
837 ref control1,
838 ref control2,
839 } => {
840 dest.write_str("curve ")?;
841 point.to_css(dest)?;
842 dest.write_str(" with ")?;
843 control1.to_css(dest)?;
844 dest.write_char(' ')?;
845 dest.write_char('/')?;
846 dest.write_char(' ')?;
847 control2.to_css(dest)
848 },
849 QuadCurve {
850 ref point,
851 ref control1,
852 } => {
853 dest.write_str("curve ")?;
854 point.to_css(dest)?;
855 dest.write_str(" with ")?;
856 control1.to_css(dest)
857 },
858 SmoothCubic {
859 ref point,
860 ref control2,
861 } => {
862 dest.write_str("smooth ")?;
863 point.to_css(dest)?;
864 dest.write_str(" with ")?;
865 control2.to_css(dest)
866 },
867 SmoothQuad { ref point } => {
868 dest.write_str("smooth ")?;
869 point.to_css(dest)
870 },
871 Arc {
872 ref point,
873 ref radii,
874 arc_sweep,
875 arc_size,
876 ref rotate,
877 } => {
878 dest.write_str("arc ")?;
879 point.to_css(dest)?;
880 dest.write_str(" of ")?;
881 radii.x.to_css(dest)?;
882 if radii.x != radii.y {
883 dest.write_char(' ')?;
884 radii.y.to_css(dest)?;
885 }
886
887 if matches!(arc_sweep, ArcSweep::Cw) {
888 dest.write_str(" cw")?;
889 }
890
891 if matches!(arc_size, ArcSize::Large) {
892 dest.write_str(" large")?;
893 }
894
895 if !rotate.is_zero() {
896 dest.write_str(" rotate ")?;
897 rotate.to_css(dest)?;
898 }
899 Ok(())
900 },
901 Close => dest.write_str("close"),
902 }
903 }
904}
905
906#[derive(
909 Animate,
910 Clone,
911 ComputeSquaredDistance,
912 Copy,
913 Debug,
914 Deserialize,
915 MallocSizeOf,
916 Parse,
917 PartialEq,
918 Serialize,
919 SpecifiedValueInfo,
920 ToAnimatedValue,
921 ToAnimatedZero,
922 ToComputedValue,
923 ToCss,
924 ToResolvedValue,
925 ToShmem,
926)]
927#[repr(u8)]
928pub enum ByTo {
929 By,
931 To,
933}
934
935impl ByTo {
936 #[inline]
938 pub fn is_abs(&self) -> bool {
939 matches!(self, ByTo::To)
940 }
941
942 #[inline]
944 pub fn new(is_abs: bool) -> Self {
945 if is_abs {
946 Self::To
947 } else {
948 Self::By
949 }
950 }
951}
952
953#[allow(missing_docs)]
957#[derive(
958 Animate,
959 Clone,
960 Copy,
961 ComputeSquaredDistance,
962 Debug,
963 Deserialize,
964 MallocSizeOf,
965 PartialEq,
966 Serialize,
967 SpecifiedValueInfo,
968 ToAnimatedValue,
969 ToAnimatedZero,
970 ToComputedValue,
971 ToResolvedValue,
972 ToShmem,
973)]
974#[repr(C, u8)]
975pub enum CommandEndPoint<LengthPercentage> {
976 ToPosition(ShapePosition<LengthPercentage>),
977 ByCoordinate(CoordinatePair<LengthPercentage>),
978}
979
980impl<LengthPercentage> CommandEndPoint<LengthPercentage> {
981 #[inline]
983 pub fn is_abs(&self) -> bool {
984 matches!(self, CommandEndPoint::ToPosition(_))
985 }
986}
987
988impl<LengthPercentage: ToCss> ToCss for CommandEndPoint<LengthPercentage> {
989 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
991 where
992 W: Write,
993 {
994 match self {
995 CommandEndPoint::ToPosition(pos) => {
996 dest.write_str("to ")?;
997 pos.horizontal.to_css(dest)?;
998 dest.write_char(' ')?;
999 pos.vertical.to_css(dest)
1000 },
1001 CommandEndPoint::ByCoordinate(coord) => {
1002 dest.write_str("by ")?;
1003 coord.to_css(dest)
1004 },
1005 }
1006 }
1007}
1008
1009impl<LengthPercentage: AddAssign> AddAssign<CoordinatePair<LengthPercentage>>
1010 for CommandEndPoint<LengthPercentage>
1011{
1012 fn add_assign(&mut self, other: CoordinatePair<LengthPercentage>) {
1013 match self {
1014 CommandEndPoint::ToPosition(ref mut a) => {
1015 a.horizontal += other.x;
1016 a.vertical += other.y;
1017 },
1018 CommandEndPoint::ByCoordinate(ref mut a) => {
1019 *a += other;
1020 },
1021 }
1022 }
1023}
1024
1025#[allow(missing_docs)]
1030#[derive(
1031 AddAssign,
1032 Animate,
1033 Clone,
1034 ComputeSquaredDistance,
1035 Copy,
1036 Debug,
1037 Deserialize,
1038 MallocSizeOf,
1039 PartialEq,
1040 Serialize,
1041 SpecifiedValueInfo,
1042 ToAnimatedValue,
1043 ToAnimatedZero,
1044 ToComputedValue,
1045 ToCss,
1046 ToResolvedValue,
1047 ToShmem,
1048)]
1049#[repr(C)]
1050pub struct CoordinatePair<LengthPercentage> {
1051 pub x: LengthPercentage,
1052 pub y: LengthPercentage,
1053}
1054
1055impl<LengthPercentage> CoordinatePair<LengthPercentage> {
1056 #[inline]
1058 pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self {
1059 Self { x, y }
1060 }
1061}
1062
1063#[derive(
1067 Clone,
1068 Copy,
1069 Debug,
1070 Deserialize,
1071 FromPrimitive,
1072 MallocSizeOf,
1073 Parse,
1074 PartialEq,
1075 Serialize,
1076 SpecifiedValueInfo,
1077 ToAnimatedValue,
1078 ToAnimatedZero,
1079 ToComputedValue,
1080 ToCss,
1081 ToResolvedValue,
1082 ToShmem,
1083)]
1084#[repr(u8)]
1085pub enum ArcSweep {
1086 Ccw = 0,
1088 Cw = 1,
1090}
1091
1092impl Animate for ArcSweep {
1093 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1094 use num_traits::FromPrimitive;
1095 (*self as i32)
1098 .animate(&(*other as i32), procedure)
1099 .map(|v| ArcSweep::from_u8((v > 0) as u8).unwrap_or(ArcSweep::Ccw))
1100 }
1101}
1102
1103impl ComputeSquaredDistance for ArcSweep {
1104 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1105 (*self as i32).compute_squared_distance(&(*other as i32))
1106 }
1107}
1108
1109#[derive(
1113 Clone,
1114 Copy,
1115 Debug,
1116 Deserialize,
1117 FromPrimitive,
1118 MallocSizeOf,
1119 Parse,
1120 PartialEq,
1121 Serialize,
1122 SpecifiedValueInfo,
1123 ToAnimatedValue,
1124 ToAnimatedZero,
1125 ToComputedValue,
1126 ToCss,
1127 ToResolvedValue,
1128 ToShmem,
1129)]
1130#[repr(u8)]
1131pub enum ArcSize {
1132 Small = 0,
1134 Large = 1,
1136}
1137
1138impl Animate for ArcSize {
1139 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
1140 use num_traits::FromPrimitive;
1141 (*self as i32)
1144 .animate(&(*other as i32), procedure)
1145 .map(|v| ArcSize::from_u8((v > 0) as u8).unwrap_or(ArcSize::Small))
1146 }
1147}
1148
1149impl ComputeSquaredDistance for ArcSize {
1150 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
1151 (*self as i32).compute_squared_distance(&(*other as i32))
1152 }
1153}