1use crate::color::AbsoluteColor;
12use crate::properties::{ComputedValues, PropertyId};
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()
281 .map(|v| v.to_animated_value(context))
282 .collect()
283 }
284
285 #[inline]
286 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
287 animated.into_iter().map(T::from_animated_value).collect()
288 }
289}
290
291impl<T> ToAnimatedValue for thin_vec::ThinVec<T>
292where
293 T: ToAnimatedValue,
294{
295 type AnimatedValue = thin_vec::ThinVec<<T as ToAnimatedValue>::AnimatedValue>;
296
297 #[inline]
298 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
299 self.into_iter()
300 .map(|v| v.to_animated_value(context))
301 .collect()
302 }
303
304 #[inline]
305 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
306 animated.into_iter().map(T::from_animated_value).collect()
307 }
308}
309
310impl<T> ToAnimatedValue for Box<T>
311where
312 T: ToAnimatedValue,
313{
314 type AnimatedValue = Box<<T as ToAnimatedValue>::AnimatedValue>;
315
316 #[inline]
317 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
318 Box::new((*self).to_animated_value(context))
319 }
320
321 #[inline]
322 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
323 Box::new(T::from_animated_value(*animated))
324 }
325}
326
327impl<T> ToAnimatedValue for Box<[T]>
328where
329 T: ToAnimatedValue,
330{
331 type AnimatedValue = Box<[<T as ToAnimatedValue>::AnimatedValue]>;
332
333 #[inline]
334 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
335 self.into_vec()
336 .into_iter()
337 .map(|v| v.to_animated_value(context))
338 .collect()
339 }
340
341 #[inline]
342 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
343 animated
344 .into_vec()
345 .into_iter()
346 .map(T::from_animated_value)
347 .collect()
348 }
349}
350
351impl<T> ToAnimatedValue for crate::OwnedSlice<T>
352where
353 T: ToAnimatedValue,
354{
355 type AnimatedValue = crate::OwnedSlice<<T as ToAnimatedValue>::AnimatedValue>;
356
357 #[inline]
358 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
359 self.into_box().to_animated_value(context).into()
360 }
361
362 #[inline]
363 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
364 Self::from(Box::from_animated_value(animated.into_box()))
365 }
366}
367
368impl<T> ToAnimatedValue for SmallVec<[T; 1]>
369where
370 T: ToAnimatedValue,
371{
372 type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;
373
374 #[inline]
375 fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
376 self.into_iter()
377 .map(|v| v.to_animated_value(context))
378 .collect()
379 }
380
381 #[inline]
382 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
383 animated.into_iter().map(T::from_animated_value).collect()
384 }
385}
386
387macro_rules! trivial_to_animated_value {
388 ($ty:ty) => {
389 impl $crate::values::animated::ToAnimatedValue for $ty {
390 type AnimatedValue = Self;
391
392 #[inline]
393 fn to_animated_value(self, _: &Context) -> Self {
394 self
395 }
396
397 #[inline]
398 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
399 animated
400 }
401 }
402 };
403}
404
405trivial_to_animated_value!(crate::Atom);
406trivial_to_animated_value!(Angle);
407trivial_to_animated_value!(ComputedUrl);
408trivial_to_animated_value!(bool);
409trivial_to_animated_value!(f32);
410trivial_to_animated_value!(i32);
411trivial_to_animated_value!(u32);
412trivial_to_animated_value!(usize);
413trivial_to_animated_value!(AbsoluteColor);
414trivial_to_animated_value!(crate::values::generics::color::ColorMixFlags);
415trivial_to_animated_value!(SVGPathData);
424trivial_to_animated_value!(Image);
428
429impl ToAnimatedZero for Au {
430 #[inline]
431 fn to_animated_zero(&self) -> Result<Self, ()> {
432 Ok(Au(0))
433 }
434}
435
436impl ToAnimatedZero for f32 {
437 #[inline]
438 fn to_animated_zero(&self) -> Result<Self, ()> {
439 Ok(0.)
440 }
441}
442
443impl ToAnimatedZero for f64 {
444 #[inline]
445 fn to_animated_zero(&self) -> Result<Self, ()> {
446 Ok(0.)
447 }
448}
449
450impl ToAnimatedZero for i32 {
451 #[inline]
452 fn to_animated_zero(&self) -> Result<Self, ()> {
453 Ok(0)
454 }
455}
456
457impl<T> ToAnimatedZero for Box<T>
458where
459 T: ToAnimatedZero,
460{
461 #[inline]
462 fn to_animated_zero(&self) -> Result<Self, ()> {
463 Ok(Box::new((**self).to_animated_zero()?))
464 }
465}
466
467impl<T> ToAnimatedZero for Option<T>
468where
469 T: ToAnimatedZero,
470{
471 #[inline]
472 fn to_animated_zero(&self) -> Result<Self, ()> {
473 match *self {
474 Some(ref value) => Ok(Some(value.to_animated_zero()?)),
475 None => Ok(None),
476 }
477 }
478}
479
480impl<T> ToAnimatedZero for Vec<T>
481where
482 T: ToAnimatedZero,
483{
484 #[inline]
485 fn to_animated_zero(&self) -> Result<Self, ()> {
486 self.iter().map(|v| v.to_animated_zero()).collect()
487 }
488}
489
490impl<T> ToAnimatedZero for thin_vec::ThinVec<T>
491where
492 T: ToAnimatedZero,
493{
494 #[inline]
495 fn to_animated_zero(&self) -> Result<Self, ()> {
496 self.iter().map(|v| v.to_animated_zero()).collect()
497 }
498}
499
500impl<T> ToAnimatedZero for Box<[T]>
501where
502 T: ToAnimatedZero,
503{
504 #[inline]
505 fn to_animated_zero(&self) -> Result<Self, ()> {
506 self.iter().map(|v| v.to_animated_zero()).collect()
507 }
508}
509
510impl<T> ToAnimatedZero for crate::OwnedSlice<T>
511where
512 T: ToAnimatedZero,
513{
514 #[inline]
515 fn to_animated_zero(&self) -> Result<Self, ()> {
516 self.iter().map(|v| v.to_animated_zero()).collect()
517 }
518}
519
520impl<T> ToAnimatedZero for crate::ArcSlice<T>
521where
522 T: ToAnimatedZero,
523{
524 #[inline]
525 fn to_animated_zero(&self) -> Result<Self, ()> {
526 let v = self
527 .iter()
528 .map(|v| v.to_animated_zero())
529 .collect::<Result<Vec<_>, _>>()?;
530 Ok(crate::ArcSlice::from_iter(v.into_iter()))
531 }
532}