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:expr,
74 $to_as_shape:expr
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(from), Self::Path(to)) => from.animate(to, procedure).map(Self::Path),
113 (Self::Shape(from), Self::Shape(to)) => from.animate(to, procedure).map(Self::Shape),
114 (Self::Shape(from), Self::Path(to)) => {
115 animate_shape!(
118 from,
119 to,
120 procedure,
121 (|shape_cmd| shape_cmd),
122 ShapeCommand::from
123 )
124 .map(Self::Shape)
125 },
126 (Self::Path(from), Self::Shape(to)) => {
127 animate_shape!(
130 from,
131 to,
132 procedure,
133 ShapeCommand::from,
134 (|shape_cmd| shape_cmd)
135 )
136 .map(Self::Shape)
137 },
138 }
139 }
140}
141
142impl From<&PathCommand> for ShapeCommand {
143 #[inline]
144 fn from(path: &PathCommand) -> Self {
145 match path {
146 &PathCommand::Close => Self::Close,
147 PathCommand::Move { point } => Self::Move {
148 point: point.into(),
149 },
150 PathCommand::Line { point } => Self::Move {
151 point: point.into(),
152 },
153 PathCommand::HLine { x } => Self::HLine { x: x.into() },
154 PathCommand::VLine { y } => Self::VLine { y: y.into() },
155 PathCommand::CubicCurve {
156 point,
157 control1,
158 control2,
159 } => Self::CubicCurve {
160 point: point.into(),
161 control1: control1.into(),
162 control2: control2.into(),
163 },
164 PathCommand::QuadCurve { point, control1 } => Self::QuadCurve {
165 point: point.into(),
166 control1: control1.into(),
167 },
168 PathCommand::SmoothCubic { point, control2 } => Self::SmoothCubic {
169 point: point.into(),
170 control2: control2.into(),
171 },
172 PathCommand::SmoothQuad { point } => Self::SmoothQuad {
173 point: point.into(),
174 },
175 &PathCommand::Arc {
176 ref point,
177 ref radii,
178 arc_sweep,
179 arc_size,
180 rotate,
181 } => Self::Arc {
182 point: point.into(),
183 radii: radii.into(),
184 arc_sweep,
185 arc_size,
186 rotate: Angle::from_degrees(rotate),
187 },
188 }
189 }
190}
191
192impl From<&CoordPair> for CoordinatePair {
193 #[inline]
194 fn from(p: &CoordPair) -> Self {
195 use crate::values::computed::CSSPixelLength;
196 Self::new(
197 LengthPercentage::new_length(CSSPixelLength::new(p.x)),
198 LengthPercentage::new_length(CSSPixelLength::new(p.y)),
199 )
200 }
201}
202
203impl From<&SVGPathPosition> for Position {
204 #[inline]
205 fn from(p: &SVGPathPosition) -> Self {
206 use crate::values::computed::CSSPixelLength;
207 Self::new(
208 LengthPercentage::new_length(CSSPixelLength::new(p.horizontal)),
209 LengthPercentage::new_length(CSSPixelLength::new(p.vertical)),
210 )
211 }
212}
213
214impl From<&generic::CommandEndPoint<SVGPathPosition, CSSFloat>> for CommandEndPoint {
215 #[inline]
216 fn from(p: &generic::CommandEndPoint<SVGPathPosition, CSSFloat>) -> Self {
217 match p {
218 generic::CommandEndPoint::ToPosition(pos) => Self::ToPosition(pos.into()),
219 generic::CommandEndPoint::ByCoordinate(coord) => Self::ByCoordinate(coord.into()),
220 }
221 }
222}
223
224impl From<&generic::AxisEndPoint<CSSFloat>> for AxisEndPoint {
225 #[inline]
226 fn from(p: &generic::AxisEndPoint<CSSFloat>) -> Self {
227 use crate::values::computed::CSSPixelLength;
228 use generic::AxisPosition;
229 match p {
230 generic::AxisEndPoint::ToPosition(AxisPosition::LengthPercent(lp)) => Self::ToPosition(
231 AxisPosition::LengthPercent(LengthPercentage::new_length(CSSPixelLength::new(*lp))),
232 ),
233 generic::AxisEndPoint::ToPosition(AxisPosition::Keyword(_)) => {
234 unreachable!("Invalid state: SVG path commands cannot contain a keyword.")
235 },
236 generic::AxisEndPoint::ByCoordinate(pos) => {
237 Self::ByCoordinate(LengthPercentage::new_length(CSSPixelLength::new(*pos)))
238 },
239 }
240 }
241}
242
243impl From<&generic::ControlPoint<SVGPathPosition, CSSFloat>> for ControlPoint {
244 #[inline]
245 fn from(p: &generic::ControlPoint<SVGPathPosition, CSSFloat>) -> Self {
246 match p {
247 generic::ControlPoint::Absolute(pos) => Self::Absolute(pos.into()),
248 generic::ControlPoint::Relative(point) => Self::Relative(RelativeControlPoint {
249 coord: CoordinatePair::from(&point.coord),
250 reference: point.reference,
251 }),
252 }
253 }
254}
255
256impl From<&generic::ArcRadii<CSSFloat>> for generic::ArcRadii<LengthPercentage> {
257 #[inline]
258 fn from(p: &generic::ArcRadii<CSSFloat>) -> Self {
259 use crate::values::computed::CSSPixelLength;
260 Self {
261 rx: LengthPercentage::new_length(CSSPixelLength::new(p.rx)),
262 ry: p
263 .ry
264 .map(|v| LengthPercentage::new_length(CSSPixelLength::new(v))),
265 }
266 }
267}