use crate::color::AbsoluteColor;
use crate::properties::{PropertyId, ComputedValues};
use crate::values::computed::url::ComputedUrl;
use crate::values::computed::{Angle, Image, Length};
use crate::values::specified::SVGPathData;
use crate::values::CSSFloat;
use app_units::Au;
use smallvec::SmallVec;
use std::cmp;
pub mod color;
pub mod effects;
mod font;
mod grid;
pub mod lists;
mod svg;
pub mod transform;
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
enum PropertyCategory {
Custom,
PhysicalLonghand,
LogicalLonghand,
Shorthand,
}
impl PropertyCategory {
fn of(id: &PropertyId) -> Self {
match *id {
PropertyId::NonCustom(id) => match id.longhand_or_shorthand() {
Ok(id) => {
if id.is_logical() {
PropertyCategory::LogicalLonghand
} else {
PropertyCategory::PhysicalLonghand
}
},
Err(..) => PropertyCategory::Shorthand,
},
PropertyId::Custom(..) => PropertyCategory::Custom,
}
}
}
pub fn compare_property_priority(a: &PropertyId, b: &PropertyId) -> cmp::Ordering {
let a_category = PropertyCategory::of(a);
let b_category = PropertyCategory::of(b);
if a_category != b_category {
return a_category.cmp(&b_category);
}
if a_category != PropertyCategory::Shorthand {
return cmp::Ordering::Equal;
}
let a = a.as_shorthand().unwrap();
let b = b.as_shorthand().unwrap();
let subprop_count_a = a.longhands().count();
let subprop_count_b = b.longhands().count();
subprop_count_a
.cmp(&subprop_count_b)
.then_with(|| a.idl_name_sort_order().cmp(&b.idl_name_sort_order()))
}
pub fn animate_multiplicative_factor(
this: CSSFloat,
other: CSSFloat,
procedure: Procedure,
) -> Result<CSSFloat, ()> {
Ok((this - 1.).animate(&(other - 1.), procedure)? + 1.)
}
pub trait Animate: Sized {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Procedure {
Interpolate { progress: f64 },
Add,
Accumulate { count: u64 },
}
pub struct Context<'a> {
pub style: &'a ComputedValues,
}
pub trait ToAnimatedValue {
type AnimatedValue;
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue;
fn from_animated_value(animated: Self::AnimatedValue) -> Self;
}
pub trait ToAnimatedZero: Sized {
fn to_animated_zero(&self) -> Result<Self, ()>;
}
impl Procedure {
#[inline]
pub fn weights(self) -> (f64, f64) {
match self {
Procedure::Interpolate { progress } => (1. - progress, progress),
Procedure::Add => (1., 1.),
Procedure::Accumulate { count } => (count as f64, 1.),
}
}
}
impl Animate for i32 {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(((*self as f64).animate(&(*other as f64), procedure)? + 0.5).floor() as i32)
}
}
impl Animate for f32 {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
let ret = (*self as f64).animate(&(*other as f64), procedure)?;
Ok(ret.min(f32::MAX as f64).max(f32::MIN as f64) as f32)
}
}
impl Animate for f64 {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
let (self_weight, other_weight) = procedure.weights();
let ret = *self * self_weight + *other * other_weight;
Ok(ret.min(f64::MAX).max(f64::MIN))
}
}
impl<T> Animate for Option<T>
where
T: Animate,
{
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self.as_ref(), other.as_ref()) {
(Some(ref this), Some(ref other)) => Ok(Some(this.animate(other, procedure)?)),
(None, None) => Ok(None),
_ => Err(()),
}
}
}
impl ToAnimatedValue for Au {
type AnimatedValue = Length;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
Length::new(self.to_f32_px()).to_animated_value(context)
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
Au::from_f32_px(Length::from_animated_value(animated).px())
}
}
impl<T: Animate> Animate for Box<T> {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Box::new((**self).animate(&other, procedure)?))
}
}
impl<T> ToAnimatedValue for Option<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
self.map(|v| T::to_animated_value(v, context))
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.map(T::from_animated_value)
}
}
impl<T> ToAnimatedValue for Vec<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = Vec<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
self.into_iter().map(|v| v.to_animated_value(context)).collect()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.into_iter().map(T::from_animated_value).collect()
}
}
impl<T> ToAnimatedValue for thin_vec::ThinVec<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = thin_vec::ThinVec<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
self.into_iter().map(|v| v.to_animated_value(context)).collect()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.into_iter().map(T::from_animated_value).collect()
}
}
impl<T> ToAnimatedValue for Box<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = Box<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
Box::new((*self).to_animated_value(context))
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
Box::new(T::from_animated_value(*animated))
}
}
impl<T> ToAnimatedValue for Box<[T]>
where
T: ToAnimatedValue,
{
type AnimatedValue = Box<[<T as ToAnimatedValue>::AnimatedValue]>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
self.into_vec()
.into_iter()
.map(|v| v.to_animated_value(context))
.collect()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated
.into_vec()
.into_iter()
.map(T::from_animated_value)
.collect()
}
}
impl<T> ToAnimatedValue for crate::OwnedSlice<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = crate::OwnedSlice<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
self.into_box().to_animated_value(context).into()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
Self::from(Box::from_animated_value(animated.into_box()))
}
}
impl<T> ToAnimatedValue for SmallVec<[T; 1]>
where
T: ToAnimatedValue,
{
type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;
#[inline]
fn to_animated_value(self, context: &Context) -> Self::AnimatedValue {
self.into_iter().map(|v| v.to_animated_value(context)).collect()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.into_iter().map(T::from_animated_value).collect()
}
}
macro_rules! trivial_to_animated_value {
($ty:ty) => {
impl $crate::values::animated::ToAnimatedValue for $ty {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self, _: &Context) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated
}
}
};
}
trivial_to_animated_value!(crate::Atom);
trivial_to_animated_value!(Angle);
trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool);
trivial_to_animated_value!(f32);
trivial_to_animated_value!(i32);
trivial_to_animated_value!(u32);
trivial_to_animated_value!(usize);
trivial_to_animated_value!(AbsoluteColor);
trivial_to_animated_value!(crate::values::generics::color::ColorMixFlags);
trivial_to_animated_value!(SVGPathData);
trivial_to_animated_value!(Image);
impl ToAnimatedZero for Au {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(Au(0))
}
}
impl ToAnimatedZero for f32 {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(0.)
}
}
impl ToAnimatedZero for f64 {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(0.)
}
}
impl ToAnimatedZero for i32 {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(0)
}
}
impl<T> ToAnimatedZero for Box<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(Box::new((**self).to_animated_zero()?))
}
}
impl<T> ToAnimatedZero for Option<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
Some(ref value) => Ok(Some(value.to_animated_zero()?)),
None => Ok(None),
}
}
}
impl<T> ToAnimatedZero for Vec<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
self.iter().map(|v| v.to_animated_zero()).collect()
}
}
impl<T> ToAnimatedZero for thin_vec::ThinVec<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
self.iter().map(|v| v.to_animated_zero()).collect()
}
}
impl<T> ToAnimatedZero for Box<[T]>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
self.iter().map(|v| v.to_animated_zero()).collect()
}
}
impl<T> ToAnimatedZero for crate::OwnedSlice<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
self.iter().map(|v| v.to_animated_zero()).collect()
}
}
impl<T> ToAnimatedZero for crate::ArcSlice<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
let v = self
.iter()
.map(|v| v.to_animated_zero())
.collect::<Result<Vec<_>, _>>()?;
Ok(crate::ArcSlice::from_iter(v.into_iter()))
}
}