Skip to main content

style/values/animated/
color.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Animated types for CSS colors.
6
7use style_traits::owned_slice::OwnedSlice;
8
9use crate::color::mix::ColorInterpolationMethod;
10use crate::color::AbsoluteColor;
11use crate::values::animated::{Animate, Procedure, ToAnimatedZero};
12use crate::values::computed::Percentage;
13use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
14use crate::values::generics::color::{
15    ColorMixFlags, GenericColor, GenericColorMix, GenericColorMixItem,
16};
17use crate::values::generics::Optional;
18
19impl Animate for AbsoluteColor {
20    #[inline]
21    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
22        use crate::color::mix;
23
24        let (left_weight, right_weight) = procedure.weights();
25
26        Ok(mix::mix_many(
27            ColorInterpolationMethod::best_interpolation_between(self, other),
28            [
29                mix::ColorMixItem::new(*self, left_weight as f32),
30                mix::ColorMixItem::new(*other, right_weight as f32),
31            ],
32            ColorMixFlags::empty(),
33        ))
34    }
35}
36
37impl ComputeSquaredDistance for AbsoluteColor {
38    #[inline]
39    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
40        let start = [
41            self.alpha,
42            self.components.0 * self.alpha,
43            self.components.1 * self.alpha,
44            self.components.2 * self.alpha,
45        ];
46        let end = [
47            other.alpha,
48            other.components.0 * other.alpha,
49            other.components.1 * other.alpha,
50            other.components.2 * other.alpha,
51        ];
52        start
53            .iter()
54            .zip(&end)
55            .map(|(this, other)| this.compute_squared_distance(other))
56            .sum()
57    }
58}
59
60/// An animated value for `<color>`.
61pub type Color = GenericColor<Percentage>;
62
63/// An animated value for `<color-mix>`.
64pub type ColorMix = GenericColorMix<Color, Percentage>;
65
66impl Animate for Color {
67    #[inline]
68    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
69        let (left_weight, right_weight) = procedure.weights();
70
71        Ok(Self::from_color_mix(ColorMix {
72            interpolation: ColorInterpolationMethod::srgb(),
73            items: OwnedSlice::from_slice(&[
74                GenericColorMixItem {
75                    color: self.clone(),
76                    percentage: Optional::Some(Percentage(left_weight as f32)),
77                },
78                GenericColorMixItem {
79                    color: other.clone(),
80                    percentage: Optional::Some(Percentage(right_weight as f32)),
81                },
82            ]),
83            // See https://github.com/w3c/csswg-drafts/issues/7324
84            flags: ColorMixFlags::empty(),
85        }))
86    }
87}
88
89impl ComputeSquaredDistance for Color {
90    #[inline]
91    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
92        let current_color = AbsoluteColor::TRANSPARENT_BLACK;
93        self.resolve_to_absolute(&current_color)
94            .compute_squared_distance(&other.resolve_to_absolute(&current_color))
95    }
96}
97
98impl ToAnimatedZero for Color {
99    #[inline]
100    fn to_animated_zero(&self) -> Result<Self, ()> {
101        Ok(Color::Absolute(AbsoluteColor::TRANSPARENT_BLACK))
102    }
103}