1use crate::values::animated::{Animate, Procedure};
11use crate::values::computed::angle::Angle;
12use crate::values::computed::url::ComputedUrl;
13use crate::values::computed::{Image, LengthPercentage, Position};
14use crate::values::generics::basic_shape as generic;
15use crate::values::specified::svg_path::{CoordPair, PathCommand, SVGPathPosition};
16use crate::values::CSSFloat;
17
18pub use crate::values::generics::basic_shape::FillRule;
20
21pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>;
23
24pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
26
27pub type BasicShape = generic::GenericBasicShape<Angle, Position, LengthPercentage, InsetRect>;
29
30pub type InsetRect = generic::GenericInsetRect<LengthPercentage>;
32
33pub type Circle = generic::Circle<Position, LengthPercentage>;
35
36pub type Ellipse = generic::Ellipse<Position, LengthPercentage>;
38
39pub type ShapeRadius = generic::GenericShapeRadius<LengthPercentage>;
41
42pub type Shape = generic::Shape<Angle, Position, LengthPercentage>;
44
45pub type ShapeCommand = generic::GenericShapeCommand<Angle, Position, LengthPercentage>;
47
48pub type PathOrShapeFunction =
50 generic::GenericPathOrShapeFunction<Angle, Position, LengthPercentage>;
51
52pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>;
54
55pub type ControlPoint = generic::ControlPoint<Position, LengthPercentage>;
57
58pub type RelativeControlPoint = generic::RelativeControlPoint<LengthPercentage>;
60
61pub type CommandEndPoint = generic::CommandEndPoint<Position, LengthPercentage>;
63
64pub type AxisEndPoint = generic::AxisEndPoint<LengthPercentage>;
66
67macro_rules! animate_shape {
69 (
70 $from:ident,
71 $to:ident,
72 $procedure:ident,
73 $from_as_shape:tt,
74 $to_as_shape:tt
75 ) => {{
76 if $from.fill != $to.fill {
78 return Err(());
79 }
80
81 let from_cmds = $from.commands();
83 let to_cmds = $to.commands();
84 if from_cmds.len() != to_cmds.len() {
85 return Err(());
86 }
87 let commands = from_cmds
88 .iter()
89 .zip(to_cmds.iter())
90 .map(|(from_cmd, to_cmd)| {
91 $from_as_shape(from_cmd).animate(&$to_as_shape(to_cmd), $procedure)
92 })
93 .collect::<Result<Vec<ShapeCommand>, ()>>()?;
94
95 Ok(Shape {
96 fill: $from.fill,
97 commands: commands.into(),
98 })
99 }};
100}
101
102impl Animate for PathOrShapeFunction {
103 #[inline]
104 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
105 match (self, other) {
112 (Self::Path(ref from), Self::Path(ref to)) => {
113 from.animate(to, procedure).map(Self::Path)
114 },
115 (Self::Shape(ref from), Self::Shape(ref to)) => {
116 from.animate(to, procedure).map(Self::Shape)
117 },
118 (Self::Shape(ref from), Self::Path(ref to)) => {
119 animate_shape!(
122 from,
123 to,
124 procedure,
125 (|shape_cmd| shape_cmd),
126 (|path_cmd| ShapeCommand::from(path_cmd))
127 )
128 .map(Self::Shape)
129 },
130 (Self::Path(ref from), Self::Shape(ref to)) => {
131 animate_shape!(
134 from,
135 to,
136 procedure,
137 (|path_cmd| ShapeCommand::from(path_cmd)),
138 (|shape_cmd| shape_cmd)
139 )
140 .map(Self::Shape)
141 },
142 }
143 }
144}
145
146impl From<&PathCommand> for ShapeCommand {
147 #[inline]
148 fn from(path: &PathCommand) -> Self {
149 match path {
150 &PathCommand::Close => Self::Close,
151 &PathCommand::Move { ref point } => Self::Move {
152 point: point.into(),
153 },
154 &PathCommand::Line { ref point } => Self::Move {
155 point: point.into(),
156 },
157 &PathCommand::HLine { ref x } => Self::HLine { x: x.into() },
158 &PathCommand::VLine { ref y } => Self::VLine { y: y.into() },
159 &PathCommand::CubicCurve {
160 ref point,
161 ref control1,
162 ref control2,
163 } => Self::CubicCurve {
164 point: point.into(),
165 control1: control1.into(),
166 control2: control2.into(),
167 },
168 &PathCommand::QuadCurve {
169 ref point,
170 ref control1,
171 } => Self::QuadCurve {
172 point: point.into(),
173 control1: control1.into(),
174 },
175 &PathCommand::SmoothCubic {
176 ref point,
177 ref control2,
178 } => Self::SmoothCubic {
179 point: point.into(),
180 control2: control2.into(),
181 },
182 &PathCommand::SmoothQuad { ref point } => Self::SmoothQuad {
183 point: point.into(),
184 },
185 &PathCommand::Arc {
186 ref point,
187 ref radii,
188 arc_sweep,
189 arc_size,
190 rotate,
191 } => Self::Arc {
192 point: point.into(),
193 radii: radii.into(),
194 arc_sweep,
195 arc_size,
196 rotate: Angle::from_degrees(rotate),
197 },
198 }
199 }
200}
201
202impl From<&CoordPair> for CoordinatePair {
203 #[inline]
204 fn from(p: &CoordPair) -> Self {
205 use crate::values::computed::CSSPixelLength;
206 Self::new(
207 LengthPercentage::new_length(CSSPixelLength::new(p.x)),
208 LengthPercentage::new_length(CSSPixelLength::new(p.y)),
209 )
210 }
211}
212
213impl From<&SVGPathPosition> for Position {
214 #[inline]
215 fn from(p: &SVGPathPosition) -> Self {
216 use crate::values::computed::CSSPixelLength;
217 Self::new(
218 LengthPercentage::new_length(CSSPixelLength::new(p.horizontal)),
219 LengthPercentage::new_length(CSSPixelLength::new(p.vertical)),
220 )
221 }
222}
223
224impl From<&generic::CommandEndPoint<SVGPathPosition, CSSFloat>> for CommandEndPoint {
225 #[inline]
226 fn from(p: &generic::CommandEndPoint<SVGPathPosition, CSSFloat>) -> Self {
227 match p {
228 generic::CommandEndPoint::ToPosition(pos) => Self::ToPosition(pos.into()),
229 generic::CommandEndPoint::ByCoordinate(coord) => Self::ByCoordinate(coord.into()),
230 }
231 }
232}
233
234impl From<&generic::AxisEndPoint<CSSFloat>> for AxisEndPoint {
235 #[inline]
236 fn from(p: &generic::AxisEndPoint<CSSFloat>) -> Self {
237 use crate::values::computed::CSSPixelLength;
238 use generic::AxisPosition;
239 match p {
240 generic::AxisEndPoint::ToPosition(AxisPosition::LengthPercent(lp)) => Self::ToPosition(
241 AxisPosition::LengthPercent(LengthPercentage::new_length(CSSPixelLength::new(*lp))),
242 ),
243 generic::AxisEndPoint::ToPosition(AxisPosition::Keyword(_)) => {
244 unreachable!("Invalid state: SVG path commands cannot contain a keyword.")
245 },
246 generic::AxisEndPoint::ByCoordinate(pos) => {
247 Self::ByCoordinate(LengthPercentage::new_length(CSSPixelLength::new(*pos)))
248 },
249 }
250 }
251}
252
253impl From<&generic::ControlPoint<SVGPathPosition, CSSFloat>> for ControlPoint {
254 #[inline]
255 fn from(p: &generic::ControlPoint<SVGPathPosition, CSSFloat>) -> Self {
256 match p {
257 generic::ControlPoint::Absolute(pos) => Self::Absolute(pos.into()),
258 generic::ControlPoint::Relative(point) => Self::Relative(RelativeControlPoint {
259 coord: CoordinatePair::from(&point.coord),
260 reference: point.reference,
261 }),
262 }
263 }
264}
265
266impl From<&generic::ArcRadii<CSSFloat>> for generic::ArcRadii<LengthPercentage> {
267 #[inline]
268 fn from(p: &generic::ArcRadii<CSSFloat>) -> Self {
269 use crate::values::computed::CSSPixelLength;
270 Self {
271 rx: LengthPercentage::new_length(CSSPixelLength::new(p.rx)),
272 ry: p
273 .ry
274 .map(|v| LengthPercentage::new_length(CSSPixelLength::new(v))),
275 }
276 }
277}