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::generics::basic_shape::ShapePosition;
16use crate::values::specified::svg_path::{CoordPair, PathCommand};
17use crate::values::CSSFloat;
18
19pub use crate::values::generics::basic_shape::FillRule;
21
22pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>;
24
25pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
27
28pub type BasicShape = generic::GenericBasicShape<Angle, Position, LengthPercentage, InsetRect>;
30
31pub type InsetRect = generic::GenericInsetRect<LengthPercentage>;
33
34pub type Circle = generic::Circle<LengthPercentage>;
36
37pub type Ellipse = generic::Ellipse<LengthPercentage>;
39
40pub type ShapeRadius = generic::GenericShapeRadius<LengthPercentage>;
42
43pub type Shape = generic::Shape<Angle, Position, LengthPercentage>;
45
46pub type ShapeCommand = generic::GenericShapeCommand<Angle, Position, LengthPercentage>;
48
49pub type PathOrShapeFunction =
51 generic::GenericPathOrShapeFunction<Angle, Position, LengthPercentage>;
52
53pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>;
55
56pub type ControlPoint = generic::ControlPoint<Position, LengthPercentage>;
58
59pub type RelativeControlPoint = generic::RelativeControlPoint<LengthPercentage>;
61
62pub type CommandEndPoint = generic::CommandEndPoint<Position, LengthPercentage>;
64
65macro_rules! animate_shape {
67 (
68 $from:ident,
69 $to:ident,
70 $procedure:ident,
71 $from_as_shape:tt,
72 $to_as_shape:tt
73 ) => {{
74 if $from.fill != $to.fill {
76 return Err(());
77 }
78
79 let from_cmds = $from.commands();
81 let to_cmds = $to.commands();
82 if from_cmds.len() != to_cmds.len() {
83 return Err(());
84 }
85 let commands = from_cmds
86 .iter()
87 .zip(to_cmds.iter())
88 .map(|(from_cmd, to_cmd)| {
89 $from_as_shape(from_cmd).animate(&$to_as_shape(to_cmd), $procedure)
90 })
91 .collect::<Result<Vec<ShapeCommand>, ()>>()?;
92
93 Ok(Shape {
94 fill: $from.fill,
95 commands: commands.into(),
96 })
97 }};
98}
99
100impl Animate for PathOrShapeFunction {
101 #[inline]
102 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
103 match (self, other) {
110 (Self::Path(ref from), Self::Path(ref to)) => {
111 from.animate(to, procedure).map(Self::Path)
112 },
113 (Self::Shape(ref from), Self::Shape(ref to)) => {
114 from.animate(to, procedure).map(Self::Shape)
115 },
116 (Self::Shape(ref from), Self::Path(ref to)) => {
117 animate_shape!(
120 from,
121 to,
122 procedure,
123 (|shape_cmd| shape_cmd),
124 (|path_cmd| ShapeCommand::from(path_cmd))
125 )
126 .map(Self::Shape)
127 },
128 (Self::Path(ref from), Self::Shape(ref to)) => {
129 animate_shape!(
132 from,
133 to,
134 procedure,
135 (|path_cmd| ShapeCommand::from(path_cmd)),
136 (|shape_cmd| shape_cmd)
137 )
138 .map(Self::Shape)
139 },
140 }
141 }
142}
143
144impl From<&PathCommand> for ShapeCommand {
145 #[inline]
146 fn from(path: &PathCommand) -> Self {
147 use crate::values::computed::CSSPixelLength;
148 match path {
149 &PathCommand::Close => Self::Close,
150 &PathCommand::Move { ref point } => Self::Move {
151 point: point.into(),
152 },
153 &PathCommand::Line { ref point } => Self::Move {
154 point: point.into(),
155 },
156 &PathCommand::HLine { by_to, x } => Self::HLine {
157 by_to,
158 x: LengthPercentage::new_length(CSSPixelLength::new(x)),
159 },
160 &PathCommand::VLine { by_to, y } => Self::VLine {
161 by_to,
162 y: LengthPercentage::new_length(CSSPixelLength::new(y)),
163 },
164 &PathCommand::CubicCurve {
165 ref point,
166 ref control1,
167 ref control2,
168 } => Self::CubicCurve {
169 point: point.into(),
170 control1: control1.into(),
171 control2: control2.into(),
172 },
173 &PathCommand::QuadCurve {
174 ref point,
175 ref control1,
176 } => Self::QuadCurve {
177 point: point.into(),
178 control1: control1.into(),
179 },
180 &PathCommand::SmoothCubic {
181 ref point,
182 ref control2,
183 } => Self::SmoothCubic {
184 point: point.into(),
185 control2: control2.into(),
186 },
187 &PathCommand::SmoothQuad { ref point } => Self::SmoothQuad {
188 point: point.into(),
189 },
190 &PathCommand::Arc {
191 ref point,
192 ref radii,
193 arc_sweep,
194 arc_size,
195 rotate,
196 } => Self::Arc {
197 point: point.into(),
198 radii: radii.into(),
199 arc_sweep,
200 arc_size,
201 rotate: Angle::from_degrees(rotate),
202 },
203 }
204 }
205}
206
207impl From<&CoordPair> for CoordinatePair {
208 #[inline]
209 fn from(p: &CoordPair) -> Self {
210 use crate::values::computed::CSSPixelLength;
211 Self::new(
212 LengthPercentage::new_length(CSSPixelLength::new(p.x)),
213 LengthPercentage::new_length(CSSPixelLength::new(p.y)),
214 )
215 }
216}
217
218impl From<&ShapePosition<CSSFloat>> for Position {
219 #[inline]
220 fn from(p: &ShapePosition<CSSFloat>) -> Self {
221 use crate::values::computed::CSSPixelLength;
222 Self::new(
223 LengthPercentage::new_length(CSSPixelLength::new(p.horizontal)),
224 LengthPercentage::new_length(CSSPixelLength::new(p.vertical)),
225 )
226 }
227}
228
229impl From<&generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>> for CommandEndPoint {
230 #[inline]
231 fn from(p: &generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self {
232 match p {
233 generic::CommandEndPoint::ToPosition(pos) => Self::ToPosition(pos.into()),
234 generic::CommandEndPoint::ByCoordinate(coord) => Self::ByCoordinate(coord.into()),
235 }
236 }
237}
238
239impl From<&generic::ControlPoint<ShapePosition<CSSFloat>, CSSFloat>> for ControlPoint {
240 #[inline]
241 fn from(p: &generic::ControlPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self {
242 match p {
243 generic::ControlPoint::Absolute(pos) => Self::Absolute(pos.into()),
244 generic::ControlPoint::Relative(point) => Self::Relative(RelativeControlPoint {
245 coord: CoordinatePair::from(&point.coord),
246 reference: point.reference,
247 }),
248 }
249 }
250}
251
252impl From<&generic::ArcRadii<CSSFloat>> for generic::ArcRadii<LengthPercentage> {
253 #[inline]
254 fn from(p: &generic::ArcRadii<CSSFloat>) -> Self {
255 use crate::values::computed::CSSPixelLength;
256 Self {
257 rx: LengthPercentage::new_length(CSSPixelLength::new(p.rx)),
258 ry: p
259 .ry
260 .map(|v| LengthPercentage::new_length(CSSPixelLength::new(v))),
261 }
262 }
263}