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::generics::position::Position as GenericPosition;
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<
30 Angle,
31 Position,
32 LengthPercentage,
33 NonNegativeLengthPercentage,
34 InsetRect,
35>;
36
37pub type InsetRect = generic::GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage>;
39
40pub type Circle = generic::Circle<Position, NonNegativeLengthPercentage>;
42
43pub type Ellipse = generic::Ellipse<Position, NonNegativeLengthPercentage>;
45
46pub type ShapeRadius = generic::GenericShapeRadius<NonNegativeLengthPercentage>;
48
49pub type Shape = generic::Shape<Angle, LengthPercentage>;
51
52pub type ShapeCommand = generic::GenericShapeCommand<Angle, LengthPercentage>;
54
55pub type PathOrShapeFunction = generic::GenericPathOrShapeFunction<Angle, LengthPercentage>;
57
58pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>;
60
61pub type CommandEndPoint = generic::CommandEndPoint<LengthPercentage>;
63
64macro_rules! animate_shape {
66 (
67 $from:ident,
68 $to:ident,
69 $procedure:ident,
70 $from_as_shape:tt,
71 $to_as_shape:tt
72 ) => {{
73 if $from.fill != $to.fill {
75 return Err(());
76 }
77
78 let from_cmds = $from.commands();
80 let to_cmds = $to.commands();
81 if from_cmds.len() != to_cmds.len() {
82 return Err(());
83 }
84 let commands = from_cmds
85 .iter()
86 .zip(to_cmds.iter())
87 .map(|(from_cmd, to_cmd)| {
88 $from_as_shape(from_cmd).animate(&$to_as_shape(to_cmd), $procedure)
89 })
90 .collect::<Result<Vec<ShapeCommand>, ()>>()?;
91
92 Ok(Shape {
93 fill: $from.fill,
94 commands: commands.into(),
95 })
96 }};
97}
98
99impl Animate for PathOrShapeFunction {
100 #[inline]
101 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
102 match (self, other) {
109 (Self::Path(ref from), Self::Path(ref to)) => {
110 from.animate(to, procedure).map(Self::Path)
111 },
112 (Self::Shape(ref from), Self::Shape(ref to)) => {
113 from.animate(to, procedure).map(Self::Shape)
114 },
115 (Self::Shape(ref from), Self::Path(ref to)) => {
116 animate_shape!(
119 from,
120 to,
121 procedure,
122 (|shape_cmd| shape_cmd),
123 (|path_cmd| ShapeCommand::from(path_cmd))
124 )
125 .map(Self::Shape)
126 },
127 (Self::Path(ref from), Self::Shape(ref to)) => {
128 animate_shape!(
131 from,
132 to,
133 procedure,
134 (|path_cmd| ShapeCommand::from(path_cmd)),
135 (|shape_cmd| shape_cmd)
136 )
137 .map(Self::Shape)
138 },
139 }
140 }
141}
142
143impl From<&PathCommand> for ShapeCommand {
144 #[inline]
145 fn from(path: &PathCommand) -> Self {
146 use crate::values::computed::CSSPixelLength;
147 match path {
148 &PathCommand::Close => Self::Close,
149 &PathCommand::Move { ref point } => Self::Move {
150 point: point.into(),
151 },
152 &PathCommand::Line { ref point } => Self::Move {
153 point: point.into(),
154 },
155 &PathCommand::HLine { by_to, x } => Self::HLine {
156 by_to,
157 x: LengthPercentage::new_length(CSSPixelLength::new(x)),
158 },
159 &PathCommand::VLine { by_to, y } => Self::VLine {
160 by_to,
161 y: LengthPercentage::new_length(CSSPixelLength::new(y)),
162 },
163 &PathCommand::CubicCurve {
164 ref point,
165 ref control1,
166 ref control2,
167 } => Self::CubicCurve {
168 point: point.into(),
169 control1: control1.into(),
170 control2: control2.into(),
171 },
172 &PathCommand::QuadCurve {
173 ref point,
174 ref control1,
175 } => Self::QuadCurve {
176 point: point.into(),
177 control1: control1.into(),
178 },
179 &PathCommand::SmoothCubic {
180 ref point,
181 ref control2,
182 } => Self::SmoothCubic {
183 point: point.into(),
184 control2: control2.into(),
185 },
186 &PathCommand::SmoothQuad { ref point } => Self::SmoothQuad {
187 point: point.into(),
188 },
189 &PathCommand::Arc {
190 ref point,
191 ref radii,
192 arc_sweep,
193 arc_size,
194 rotate,
195 } => Self::Arc {
196 point: point.into(),
197 radii: radii.into(),
198 arc_sweep,
199 arc_size,
200 rotate: Angle::from_degrees(rotate),
201 },
202 }
203 }
204}
205
206impl From<&CoordPair> for CoordinatePair {
207 #[inline]
208 fn from(p: &CoordPair) -> Self {
209 use crate::values::computed::CSSPixelLength;
210 Self::new(
211 LengthPercentage::new_length(CSSPixelLength::new(p.x)),
212 LengthPercentage::new_length(CSSPixelLength::new(p.y)),
213 )
214 }
215}
216
217impl From<&GenericPosition<CSSFloat, CSSFloat>> for Position {
218 #[inline]
219 fn from(p: &GenericPosition<CSSFloat, CSSFloat>) -> Self {
220 use crate::values::computed::CSSPixelLength;
221 Self::new(
222 LengthPercentage::new_length(CSSPixelLength::new(p.horizontal)),
223 LengthPercentage::new_length(CSSPixelLength::new(p.vertical)),
224 )
225 }
226}
227
228impl From<&generic::CommandEndPoint<CSSFloat>> for CommandEndPoint {
229 #[inline]
230 fn from(p: &generic::CommandEndPoint<CSSFloat>) -> Self {
231 match p {
232 generic::CommandEndPoint::<CSSFloat>::ToPosition(pos) => {
233 CommandEndPoint::ToPosition(pos.into())
234 },
235 generic::CommandEndPoint::<CSSFloat>::ByCoordinate(coord) => {
236 CommandEndPoint::ByCoordinate(coord.into())
237 },
238 }
239 }
240}