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