1use crate::color::AbsoluteColor;
12use crate::properties::{PropertyId, ComputedValues};
13use crate::values::computed::url::ComputedUrl;
14use crate::values::computed::{Angle, Image, Length};
15use crate::values::specified::SVGPathData;
16use crate::values::CSSFloat;
17use app_units::Au;
18use smallvec::SmallVec;
19use std::cmp;
20
21pub mod color;
22pub mod effects;
23mod font;
24mod grid;
25pub mod lists;
26mod svg;
27pub mod transform;
28
29#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
33enum PropertyCategory {
34 Custom,
35 PhysicalLonghand,
36 LogicalLonghand,
37 Shorthand,
38}
39
40impl PropertyCategory {
41 fn of(id: &PropertyId) -> Self {
42 match *id {
43 PropertyId::NonCustom(id) => match id.longhand_or_shorthand() {
44 Ok(id) => {
45 if id.is_logical() {
46 PropertyCategory::LogicalLonghand
47 } else {
48 PropertyCategory::PhysicalLonghand
49 }
50 },
51 Err(..) => PropertyCategory::Shorthand,
52 },
53 PropertyId::Custom(..) => PropertyCategory::Custom,
54 }
55 }
56}
57
58pub fn compare_property_priority(a: &PropertyId, b: &PropertyId) -> cmp::Ordering {
69 let a_category = PropertyCategory::of(a);
70 let b_category = PropertyCategory::of(b);
71
72 if a_category != b_category {
73 return a_category.cmp(&b_category);
74 }
75
76 if a_category != PropertyCategory::Shorthand {
77 return cmp::Ordering::Equal;
78 }
79
80 let a = a.as_shorthand().unwrap();
81 let b = b.as_shorthand().unwrap();
82 let subprop_count_a = a.longhands().count();
85 let subprop_count_b = b.longhands().count();
86 subprop_count_a
87 .cmp(&subprop_count_b)
88 .then_with(|| a.idl_name_sort_order().cmp(&b.idl_name_sort_order()))
89}
90
91pub fn animate_multiplicative_factor(
93 this: CSSFloat,
94 other: CSSFloat,
95 procedure: Procedure,
96) -> Result<CSSFloat, ()> {
97 Ok((this - 1.).animate(&(other - 1.), procedure)? + 1.)
98}
99
100pub trait Animate: Sized {
115 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
117}
118
119#[allow(missing_docs)]
123#[derive(Clone, Copy, Debug, PartialEq)]
124pub enum Procedure {
125 Interpolate { progress: f64 },
127 Add,
129 Accumulate { count: u64 },
131}
132
133pub struct Context<'a> {
135 pub style: &'a ComputedValues,
137}
138
139pub trait ToAnimatedValue {
145 type AnimatedValue;
147
148 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue;
150
151 fn from_animated_value(animated: Self::AnimatedValue) -> Self;
153}
154
155pub trait ToAnimatedZero: Sized {
167 fn to_animated_zero(&self) -> Result<Self, ()>;
175}
176
177impl Procedure {
178 #[inline]
183 pub fn weights(self) -> (f64, f64) {
184 match self {
185 Procedure::Interpolate { progress } => (1. - progress, progress),
186 Procedure::Add => (1., 1.),
187 Procedure::Accumulate { count } => (count as f64, 1.),
188 }
189 }
190}
191
192impl Animate for i32 {
194 #[inline]
195 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
196 Ok(((*self as f64).animate(&(*other as f64), procedure)? + 0.5).floor() as i32)
197 }
198}
199
200impl Animate for f32 {
202 #[inline]
203 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
204 let ret = (*self as f64).animate(&(*other as f64), procedure)?;
205 Ok(ret.min(f32::MAX as f64).max(f32::MIN as f64) as f32)
206 }
207}
208
209impl Animate for f64 {
211 #[inline]
212 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
213 let (self_weight, other_weight) = procedure.weights();
214
215 let ret = *self * self_weight + *other * other_weight;
216 Ok(ret.min(f64::MAX).max(f64::MIN))
217 }
218}
219
220impl<T> Animate for Option<T>
221where
222 T: Animate,
223{
224 #[inline]
225 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
226 match (self.as_ref(), other.as_ref()) {
227 (Some(ref this), Some(ref other)) => Ok(Some(this.animate(other, procedure)?)),
228 (None, None) => Ok(None),
229 _ => Err(()),
230 }
231 }
232}
233
234impl ToAnimatedValue for Au {
235 type AnimatedValue = Length;
236
237 #[inline]
238 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
239 Length::new(self.to_f32_px()).to_animated_value(context)
240 }
241
242 #[inline]
243 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
244 Au::from_f32_px(Length::from_animated_value(animated).px())
245 }
246}
247
248impl<T: Animate> Animate for Box<T> {
249 #[inline]
250 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
251 Ok(Box::new((**self).animate(&other, procedure)?))
252 }
253}
254
255impl<T> ToAnimatedValue for Option<T>
256where
257 T: ToAnimatedValue,
258{
259 type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;
260
261 #[inline]
262 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
263 self.map(|v| T::to_animated_value(v, context))
264 }
265
266 #[inline]
267 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
268 animated.map(T::from_animated_value)
269 }
270}
271
272impl<T> ToAnimatedValue for Vec<T>
273where
274 T: ToAnimatedValue,
275{
276 type AnimatedValue = Vec<<T as ToAnimatedValue>::AnimatedValue>;
277
278 #[inline]
279 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
280 self.into_iter().map(|v| v.to_animated_value(context)).collect()
281 }
282
283 #[inline]
284 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
285 animated.into_iter().map(T::from_animated_value).collect()
286 }
287}
288
289impl<T> ToAnimatedValue for thin_vec::ThinVec<T>
290where
291 T: ToAnimatedValue,
292{
293 type AnimatedValue = thin_vec::ThinVec<<T as ToAnimatedValue>::AnimatedValue>;
294
295 #[inline]
296 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
297 self.into_iter().map(|v| v.to_animated_value(context)).collect()
298 }
299
300 #[inline]
301 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
302 animated.into_iter().map(T::from_animated_value).collect()
303 }
304}
305
306impl<T> ToAnimatedValue for Box<T>
307where
308 T: ToAnimatedValue,
309{
310 type AnimatedValue = Box<<T as ToAnimatedValue>::AnimatedValue>;
311
312 #[inline]
313 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
314 Box::new((*self).to_animated_value(context))
315 }
316
317 #[inline]
318 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
319 Box::new(T::from_animated_value(*animated))
320 }
321}
322
323impl<T> ToAnimatedValue for Box<[T]>
324where
325 T: ToAnimatedValue,
326{
327 type AnimatedValue = Box<[<T as ToAnimatedValue>::AnimatedValue]>;
328
329 #[inline]
330 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
331 self.into_vec()
332 .into_iter()
333 .map(|v| v.to_animated_value(context))
334 .collect()
335 }
336
337 #[inline]
338 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
339 animated
340 .into_vec()
341 .into_iter()
342 .map(T::from_animated_value)
343 .collect()
344 }
345}
346
347impl<T> ToAnimatedValue for crate::OwnedSlice<T>
348where
349 T: ToAnimatedValue,
350{
351 type AnimatedValue = crate::OwnedSlice<<T as ToAnimatedValue>::AnimatedValue>;
352
353 #[inline]
354 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
355 self.into_box().to_animated_value(context).into()
356 }
357
358 #[inline]
359 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
360 Self::from(Box::from_animated_value(animated.into_box()))
361 }
362}
363
364impl<T> ToAnimatedValue for SmallVec<[T; 1]>
365where
366 T: ToAnimatedValue,
367{
368 type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;
369
370 #[inline]
371 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
372 self.into_iter().map(|v| v.to_animated_value(context)).collect()
373 }
374
375 #[inline]
376 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
377 animated.into_iter().map(T::from_animated_value).collect()
378 }
379}
380
381macro_rules! trivial_to_animated_value {
382 ($ty:ty) => {
383 impl $crate::values::animated::ToAnimatedValue for $ty {
384 type AnimatedValue = Self;
385
386 #[inline]
387 fn to_animated_value(self, _: &Context) -> Self {
388 self
389 }
390
391 #[inline]
392 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
393 animated
394 }
395 }
396 };
397}
398
399trivial_to_animated_value!(crate::Atom);
400trivial_to_animated_value!(Angle);
401trivial_to_animated_value!(ComputedUrl);
402trivial_to_animated_value!(bool);
403trivial_to_animated_value!(f32);
404trivial_to_animated_value!(i32);
405trivial_to_animated_value!(u32);
406trivial_to_animated_value!(usize);
407trivial_to_animated_value!(AbsoluteColor);
408trivial_to_animated_value!(crate::values::generics::color::ColorMixFlags);
409trivial_to_animated_value!(SVGPathData);
418trivial_to_animated_value!(Image);
422
423impl ToAnimatedZero for Au {
424 #[inline]
425 fn to_animated_zero(&self) -> Result<Self, ()> {
426 Ok(Au(0))
427 }
428}
429
430impl ToAnimatedZero for f32 {
431 #[inline]
432 fn to_animated_zero(&self) -> Result<Self, ()> {
433 Ok(0.)
434 }
435}
436
437impl ToAnimatedZero for f64 {
438 #[inline]
439 fn to_animated_zero(&self) -> Result<Self, ()> {
440 Ok(0.)
441 }
442}
443
444impl ToAnimatedZero for i32 {
445 #[inline]
446 fn to_animated_zero(&self) -> Result<Self, ()> {
447 Ok(0)
448 }
449}
450
451impl<T> ToAnimatedZero for Box<T>
452where
453 T: ToAnimatedZero,
454{
455 #[inline]
456 fn to_animated_zero(&self) -> Result<Self, ()> {
457 Ok(Box::new((**self).to_animated_zero()?))
458 }
459}
460
461impl<T> ToAnimatedZero for Option<T>
462where
463 T: ToAnimatedZero,
464{
465 #[inline]
466 fn to_animated_zero(&self) -> Result<Self, ()> {
467 match *self {
468 Some(ref value) => Ok(Some(value.to_animated_zero()?)),
469 None => Ok(None),
470 }
471 }
472}
473
474impl<T> ToAnimatedZero for Vec<T>
475where
476 T: ToAnimatedZero,
477{
478 #[inline]
479 fn to_animated_zero(&self) -> Result<Self, ()> {
480 self.iter().map(|v| v.to_animated_zero()).collect()
481 }
482}
483
484impl<T> ToAnimatedZero for thin_vec::ThinVec<T>
485where
486 T: ToAnimatedZero,
487{
488 #[inline]
489 fn to_animated_zero(&self) -> Result<Self, ()> {
490 self.iter().map(|v| v.to_animated_zero()).collect()
491 }
492}
493
494impl<T> ToAnimatedZero for Box<[T]>
495where
496 T: ToAnimatedZero,
497{
498 #[inline]
499 fn to_animated_zero(&self) -> Result<Self, ()> {
500 self.iter().map(|v| v.to_animated_zero()).collect()
501 }
502}
503
504impl<T> ToAnimatedZero for crate::OwnedSlice<T>
505where
506 T: ToAnimatedZero,
507{
508 #[inline]
509 fn to_animated_zero(&self) -> Result<Self, ()> {
510 self.iter().map(|v| v.to_animated_zero()).collect()
511 }
512}
513
514impl<T> ToAnimatedZero for crate::ArcSlice<T>
515where
516 T: ToAnimatedZero,
517{
518 #[inline]
519 fn to_animated_zero(&self) -> Result<Self, ()> {
520 let v = self
521 .iter()
522 .map(|v| v.to_animated_zero())
523 .collect::<Result<Vec<_>, _>>()?;
524 Ok(crate::ArcSlice::from_iter(v.into_iter()))
525 }
526}