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