1use crate::values::animated::{Animate, Procedure};
11use crate::values::computed::angle::Angle;
12use crate::values::computed::url::ComputedUrl;
13use crate::values::computed::{Image, LengthPercentage, NonNegativeLengthPercentage, Position};
14use crate::values::generics::basic_shape as generic;
15use crate::values::specified::svg_path::{CoordPair, PathCommand};
16
17pub use crate::values::generics::basic_shape::FillRule;
19
20pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>;
22
23pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
25
26pub type BasicShape = generic::GenericBasicShape<
28 Angle,
29 Position,
30 LengthPercentage,
31 NonNegativeLengthPercentage,
32 InsetRect,
33>;
34
35pub type InsetRect = generic::GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage>;
37
38pub type Circle = generic::Circle<Position, NonNegativeLengthPercentage>;
40
41pub type Ellipse = generic::Ellipse<Position, NonNegativeLengthPercentage>;
43
44pub type ShapeRadius = generic::GenericShapeRadius<NonNegativeLengthPercentage>;
46
47pub type Shape = generic::Shape<Angle, LengthPercentage>;
49
50pub type ShapeCommand = generic::GenericShapeCommand<Angle, LengthPercentage>;
52
53pub type PathOrShapeFunction = generic::GenericPathOrShapeFunction<Angle, LengthPercentage>;
55
56pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>;
58
59macro_rules! animate_shape {
61 (
62 $from:ident,
63 $to:ident,
64 $procedure:ident,
65 $from_as_shape:tt,
66 $to_as_shape:tt
67 ) => {{
68 if $from.fill != $to.fill {
70 return Err(());
71 }
72
73 let from_cmds = $from.commands();
75 let to_cmds = $to.commands();
76 if from_cmds.len() != to_cmds.len() {
77 return Err(());
78 }
79 let commands = from_cmds
80 .iter()
81 .zip(to_cmds.iter())
82 .map(|(from_cmd, to_cmd)| {
83 $from_as_shape(from_cmd).animate(&$to_as_shape(to_cmd), $procedure)
84 })
85 .collect::<Result<Vec<ShapeCommand>, ()>>()?;
86
87 Ok(Shape {
88 fill: $from.fill,
89 commands: commands.into(),
90 })
91 }};
92}
93
94impl Animate for PathOrShapeFunction {
95 #[inline]
96 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
97 match (self, other) {
104 (Self::Path(ref from), Self::Path(ref to)) => {
105 from.animate(to, procedure).map(Self::Path)
106 },
107 (Self::Shape(ref from), Self::Shape(ref to)) => {
108 from.animate(to, procedure).map(Self::Shape)
109 },
110 (Self::Shape(ref from), Self::Path(ref to)) => {
111 animate_shape!(
114 from,
115 to,
116 procedure,
117 (|shape_cmd| shape_cmd),
118 (|path_cmd| ShapeCommand::from(path_cmd))
119 )
120 .map(Self::Shape)
121 },
122 (Self::Path(ref from), Self::Shape(ref to)) => {
123 animate_shape!(
126 from,
127 to,
128 procedure,
129 (|path_cmd| ShapeCommand::from(path_cmd)),
130 (|shape_cmd| shape_cmd)
131 )
132 .map(Self::Shape)
133 },
134 }
135 }
136}
137
138impl From<&PathCommand> for ShapeCommand {
139 #[inline]
140 fn from(path: &PathCommand) -> Self {
141 use crate::values::computed::CSSPixelLength;
142 match path {
143 &PathCommand::Close => Self::Close,
144 &PathCommand::Move { by_to, ref point } => Self::Move {
145 by_to,
146 point: point.into(),
147 },
148 &PathCommand::Line { by_to, ref point } => Self::Move {
149 by_to,
150 point: point.into(),
151 },
152 &PathCommand::HLine { by_to, x } => Self::HLine {
153 by_to,
154 x: LengthPercentage::new_length(CSSPixelLength::new(x)),
155 },
156 &PathCommand::VLine { by_to, y } => Self::VLine {
157 by_to,
158 y: LengthPercentage::new_length(CSSPixelLength::new(y)),
159 },
160 &PathCommand::CubicCurve {
161 by_to,
162 ref point,
163 ref control1,
164 ref control2,
165 } => Self::CubicCurve {
166 by_to,
167 point: point.into(),
168 control1: control1.into(),
169 control2: control2.into(),
170 },
171 &PathCommand::QuadCurve {
172 by_to,
173 ref point,
174 ref control1,
175 } => Self::QuadCurve {
176 by_to,
177 point: point.into(),
178 control1: control1.into(),
179 },
180 &PathCommand::SmoothCubic {
181 by_to,
182 ref point,
183 ref control2,
184 } => Self::SmoothCubic {
185 by_to,
186 point: point.into(),
187 control2: control2.into(),
188 },
189 &PathCommand::SmoothQuad { by_to, ref point } => Self::SmoothQuad {
190 by_to,
191 point: point.into(),
192 },
193 &PathCommand::Arc {
194 by_to,
195 ref point,
196 ref radii,
197 arc_sweep,
198 arc_size,
199 rotate,
200 } => Self::Arc {
201 by_to,
202 point: point.into(),
203 radii: radii.into(),
204 arc_sweep,
205 arc_size,
206 rotate: Angle::from_degrees(rotate),
207 },
208 }
209 }
210}
211
212impl From<&CoordPair> for CoordinatePair {
213 #[inline]
214 fn from(p: &CoordPair) -> Self {
215 use crate::values::computed::CSSPixelLength;
216 Self::new(
217 LengthPercentage::new_length(CSSPixelLength::new(p.x)),
218 LengthPercentage::new_length(CSSPixelLength::new(p.y)),
219 )
220 }
221}