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