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};
17
18impl Animate for AbsoluteColor {
19    #[inline]
20    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
21        use crate::color::mix;
22
23        let (left_weight, right_weight) = procedure.weights();
24
25        Ok(mix::mix_many(
26            ColorInterpolationMethod::best_interpolation_between(self, other),
27            [
28                mix::ColorMixItem::new(*self, left_weight as f32),
29                mix::ColorMixItem::new(*other, right_weight as f32),
30            ],
31            ColorMixFlags::empty(),
32        ))
33    }
34}
35
36impl ComputeSquaredDistance for AbsoluteColor {
37    #[inline]
38    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
39        let start = [
40            self.alpha,
41            self.components.0 * self.alpha,
42            self.components.1 * self.alpha,
43            self.components.2 * self.alpha,
44        ];
45        let end = [
46            other.alpha,
47            other.components.0 * other.alpha,
48            other.components.1 * other.alpha,
49            other.components.2 * other.alpha,
50        ];
51        start
52            .iter()
53            .zip(&end)
54            .map(|(this, other)| this.compute_squared_distance(other))
55            .sum()
56    }
57}
58
59/// An animated value for `<color>`.
60pub type Color = GenericColor<Percentage>;
61
62/// An animated value for `<color-mix>`.
63pub type ColorMix = GenericColorMix<Color, Percentage>;
64
65impl Animate for Color {
66    #[inline]
67    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
68        let (left_weight, right_weight) = procedure.weights();
69
70        Ok(Self::from_color_mix(ColorMix {
71            interpolation: ColorInterpolationMethod::srgb(),
72            items: OwnedSlice::from_slice(&[
73                GenericColorMixItem {
74                    color: self.clone(),
75                    percentage: Percentage(left_weight as f32),
76                },
77                GenericColorMixItem {
78                    color: other.clone(),
79                    percentage: Percentage(right_weight as f32),
80                },
81            ]),
82            // See https://github.com/w3c/csswg-drafts/issues/7324
83            flags: ColorMixFlags::empty(),
84        }))
85    }
86}
87
88impl ComputeSquaredDistance for Color {
89    #[inline]
90    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
91        let current_color = AbsoluteColor::TRANSPARENT_BLACK;
92        self.resolve_to_absolute(&current_color)
93            .compute_squared_distance(&other.resolve_to_absolute(&current_color))
94    }
95}
96
97impl ToAnimatedZero for Color {
98    #[inline]
99    fn to_animated_zero(&self) -> Result<Self, ()> {
100        Ok(Color::Absolute(AbsoluteColor::TRANSPARENT_BLACK))
101    }
102}